Developers
iPhone Duo Tab Bar: TabView and NavigationSplitView Guide
How the iPhone Duo tab bar moves to the vertical bar, which NavigationSplitView column gets one, why inspectors stay horizontal, and how to handle margins.
By AppleDuo EditorialPublished 8 min read
On this page
- Does the tab bar move to the side on iPhone Duo?
- Which bar items go vertical, and which stay horizontal?
- How do I choose whether the tab bar or toolbar compresses first?
- Can I show a sidebar instead of a tab bar on the inner display?
- Which NavigationSplitView column gets a vertical bar on iPhone Duo?
- Why does an expanded inspector keep its items horizontal?
- What size class does each NavigationSplitView column report?
- How do I lay out content next to the vertical bar without assuming padding?
- Key takeaways
Run an app with a TabView or UITabBarController on iPhone Duo and the iPhone Duo tab bar is no longer a row along the bottom of the screen. It moves to the side, into the same vertical bar that holds your navigation and toolbar items. Split views change too: in a NavigationSplitView, only one column gets that vertical bar, and an expanded inspector gets none.
This guide covers what happens to tab bars, split view columns and inspectors, how to decide which bar gives way when space runs out, and how to lay out content next to bars that are no longer symmetrical. For the general rules of the vertical bar, such as symbols, overflow and opting out, see our iPhone Duo vertical toolbar guide. Everything here comes from Apple's Raise the bar with iPhone Duo Tech Talk, Apple's documentation, a DTS summary on Apple's forums and posts by @sarunw. The APIs are new in iOS 27.0 and 27.1, and details can change between releases.
Does the tab bar move to the side on iPhone Duo?
Yes. Apple's Prepare your app for iPhone Duo talk says TabView and UITabBarController adapt to all poses, and that tabs appear on the inner and outer displays, "laying out vertically when appropriate." That means the same contexts as other bars: the outer display, and the inner display in landscape. In inner-display portrait, bars stay horizontal.
Apple describes navigation, toolbar and tab bar controls sharing one region, and suggests imagining the layout rotated 90 degrees into a vertical stack. Its examples show all three combinations: Notes uses a toolbar, Clock a tab bar, and Fitness both. As @sarunw describes it, the horizontal row of tabs "becomes a vertical stack near the bottom of the bar." Toolbar items take the top of the bar, where Apple's guidance puts Back, Close and prominent actions like Done.
You get this by building with the iOS 27.1 SDK and using the system container. An Apple DTS engineer's summary of the iPhone Duo group lab is explicit that the adaptation is tied to the containers, TabView and UITabBarController, not to standalone bars. A custom tab bar, or a UITabBar you place yourself, won't move. If you must keep one, position it with the toolbarVerticalEdge environment value or the verticalBarEdge trait, as the vertical toolbar guide explains.
Which bar items go vertical, and which stay horizontal?
Tabs follow the same item rules as the rest of the bar. Apple's Tech Talk puts it this way: items with an icon, like the back and share buttons, change their axis to vertical, while text-only items, like the edit button, stay on the horizontal axis. @sarunw's summary is the same: icon items such as back and share move to the vertical bar, and text-only items such as Edit stay horizontal.
.toolbar {
ToolbarItem(placement: .primaryAction) {
Button("Share", systemImage: "square.and.arrow.up") { share() }
}
ToolbarItem(placement: .secondaryAction) {
Button("Edit") { isEditing.toggle() }
}
}
In this sample, Share has a symbol and can go vertical. Edit has only a title, so it stays horizontal. If you want Edit in the vertical bar, give it a symbol as well; the DTS summary says the system won't present a title-only item vertically. Keep the title on every item, because the system shows it in overflow menus.
For tabs, the same advice applies to each Tab: give it a title and a systemImage, as in Tab("Recents", systemImage: "clock"). Badges are a good way to keep information without adding text. Apple's talk converts a text-and-symbol item into a symbol with .badge(7) in SwiftUI or item.badge = .count(7) in UIKit.
How do I choose whether the tab bar or toolbar compresses first?
When a tab bar and a toolbar share the vertical bar, one of them runs out of room first, especially on the outer display in landscape. Apple's talk describes two defaults for two kinds of apps. In a navigation-focused view, like Podcasts, the toolbar compresses first so primary destinations remain accessible. That's the default. In a task-oriented view, like the Games app, the tab bar compresses first to keep frequent actions visible. The bar that loses collapses into an overflow button.
SwiftUI's toolbarVerticalCompressionBehavior(_:), new in iOS 27.1, sets the preference per view. In UIKit, set verticalBarCompressionBehavior on the view controller's navigation item, also new in iOS 27.1.
TabView {
Tab("Recents", systemImage: "clock") {
NavigationStack {
RecentsView()
.toolbar {
Button("Up", systemImage: "chevron.up") { moveUp() }
Button("Down", systemImage: "chevron.down") { moveDown() }
}
.toolbarVerticalCompressionBehavior(.prefersToolbarItems)
}
}
}
navigationItem.verticalBarCompressionBehavior = .prefersBarItems
The first sample follows Apple's documentation, which uses a productivity app like Files as the example for preferring toolbar items. The second is the UIKit form from the Tech Talk. The values differ slightly between frameworks:
| Preference | SwiftUI | UIKit |
|---|---|---|
| Let the system decide (default) | .automatic | .automatic |
| Keep toolbar items visible | .prefersToolbarItems | .prefersBarItems |
| Keep the tab bar visible | .prefersTabBar | .prefersTabBar |
Within the toolbar itself, priority still matters. As @sarunw notes, set .visibilityPriority(.high) on important items so they stay visible in limited space. The vertical toolbar guide covers ordering and overflow in detail.
Can I show a sidebar instead of a tab bar on the inner display?
Yes. On iPhone, iOS shows a tab bar rather than adapting into a sidebar the way iPadOS does. On the iPhone Duo inner display, Apple lets you opt into a sidebar for richer navigation. In SwiftUI, use defaultTabBarPlacement(_:) with the sidebarAdaptable style. In UIKit, set the sidebar's preferredPlacement. Both are available from iOS 27.0.
TabView {
Tab("Home", systemImage: "house") { HomeView() }
Tab("Favorites", systemImage: "star") { FavoritesView() }
}
.tabViewStyle(.sidebarAdaptable)
.defaultTabBarPlacement(.sidebar)
tabBarController.sidebar.preferredPlacement = .sidebar
Apple's documentation says defaultTabBarPlacement(_:) applies where the style resolves to either a sidebar or a tab bar, such as iPhone, and has no effect on iPadOS, where the bar can morph. In UIKit, the automatic placement resolves to a tab bar on iOS.
One more TabView detail: if you opt out of the vertical bar with toolbarVerticalBehavior(.disabled), Apple's documentation says a TabView resolves the behavior from the selected tab. Keep the choice stable across tabs so the layout doesn't jump as people switch.
Which NavigationSplitView column gets a vertical bar on iPhone Duo?
Only the detail column. Apple's rule is that toolbar items can only move vertically when their container sits along the display edge, so in split views only the detail column participates and items from other columns stay horizontal. @sarunw sums it up: "A bar only goes vertical when its container sits along the display edge."
The DTS summary spells out the inner display: the system presents bars horizontally for the sidebar or content column, and vertically on the trailing edge for the detail column. When iPhone Duo is closed, NavigationSplitView and UISplitViewController collapse to single-stack navigation, and when open they tile or overlay their columns.
| Context | Sidebar and content columns | Detail column | Expanded inspector |
|---|---|---|---|
| Inner display, landscape | Horizontal bars | Vertical bar, trailing edge | Horizontal items |
| Inner display, portrait | Horizontal bars | Horizontal bars | Horizontal items |
| Outer display (closed) | Collapsed into one stack | Collapsed into one stack | Presented as a sheet |
The outer display row reflects Apple's collapse behavior and the inspector documentation; the stack then follows the outer display's vertical bar rules. Because the trailing-most column also decides toolbarVerticalBehavior for a split view, put any opt-out on the detail column's view.
NavigationSplitView {
SidebarList(selection: $selection)
} detail: {
DetailView(item: selection)
.toolbar {
Button("Share", systemImage: "square.and.arrow.up") { share() }
}
.inspector(isPresented: $showsInspector) {
InspectorView(item: selection)
}
}
Here the Share button lives in the detail column, so it's the item that can go vertical. Toolbar items you attach to the sidebar list stay horizontal.
Why does an expanded inspector keep its items horizontal?
Apple's Tech Talk says that since detail columns already have a vertical bar, inspectors don't receive their own when expanded, to avoid confusion. @sarunw's version: the detail column already has a vertical bar, and "a second one would compete with it."
The DTS summary adds how this fits together. On the inner display, a sidebar and an inspector can coexist when you build with NavigationSplitView and apply inspector(isPresented:content:) to the detail view. The inspector coordinates with the detail column's trailing layout instead of adding a bar. Apple's inspector documentation also says it presents as a trailing column in a horizontally regular size class and adapts to a sheet in a compact one, and the DTS answers say that on the outer display, or when the split view is collapsed, it appears as a sheet.
In practice, design inspector controls for a horizontal bar, with titles where they help. Don't rely on the vertical bar for actions that only exist in the inspector.
What size class does each NavigationSplitView column report?
The window's size classes on iPhone Duo are well documented: compact width on the outer display, regular width and height on the inner display, whatever the orientation. Our iPhone Duo size classes guide has the full table. Columns are a different question. @sarunw published a chart of the size classes of each column in NavigationSplitView on iPhone Duo, and the point to take from it is that a column doesn't have to report the window's values.
So read size classes inside the column that does the layout, not at the window or root level:
struct DetailView: View {
@Environment(\.horizontalSizeClass) private var horizontalSizeClass
let item: Item?
var body: some View {
if horizontalSizeClass == .regular {
WideDetailLayout(item: item)
} else {
CompactDetailLayout(item: item)
}
}
}
Because the environment value is read inside DetailView, it reflects the column's own traits. Apple's Strike a pose talk adds a related detail for the inner display: in a split view app like Reminders, the system keeps both columns visible by adjusting their width into an even 50/50 split. If you build panes yourself rather than columns, ArrangementView gives each pane its own size classes in a similar way.
How do I lay out content next to the vertical bar without assuming padding?
When the detail column has a vertical bar on one side and the sidebar on the other, its margins aren't the same on both edges. @sarunw's advice is short: don't assume padding, since it may not be symmetrical across devices and orientations; use layoutMarginsGuide. Apple's Tech Talk says layout margins on iPhone Duo are asymmetric like safe areas, so foreground content can sit closer to the vertical buttons while the opposite margin is preserved.
NSLayoutConstraint.activate([
headerView.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor),
headerView.trailingAnchor.constraint(equalTo: view.layoutMarginsGuide.trailingAnchor),
headerView.topAnchor.constraint(equalTo: view.layoutMarginsGuide.topAnchor)
])
Pinning to layoutMarginsGuide picks up each edge's margin separately, so nothing needs a hard-coded 16 or 20 points. Bars also lay out outside the safe area, and Apple notes that vertical bars provide leading and trailing insets rather than top and bottom ones. For the SwiftUI equivalent and the full set of inset rules, see iPhone Duo safe areas and content margins.
Key takeaways
- Use
TabVieworUITabBarController. Their tabs move into the vertical bar as a stack near the bottom; custom tab bars don't move. - Give every tab and toolbar item a symbol and a title. Icon items go vertical, text-only items stay horizontal.
- Pick which bar compresses first with
toolbarVerticalCompressionBehaviororverticalBarCompressionBehavior. By default the toolbar does. - In
NavigationSplitView, only the detail column gets a vertical bar, and an expanded inspector keeps its items horizontal. - Read size classes inside each column, and pin content to
layoutMarginsGuideinstead of assuming equal padding.
Next, work through the rest of the vertical bar rules in our vertical toolbar guide, then see how other apps and games use the device on Built for the fold.
Frequently asked questions
Does the tab bar move on iPhone Duo?
Yes. Apps built with the iOS 27.1 SDK that use TabView or UITabBarController get tabs that lay out vertically when appropriate, sharing the vertical bar with navigation and toolbar items. Custom tab bars and standalone UITabBar instances don't move.
Which NavigationSplitView column gets a vertical bar on iPhone Duo?
Only the detail column, because it's the column that sits along the display edge. On the inner display, the sidebar and content columns keep horizontal bars, and the detail column's bar goes vertical on the trailing edge.
Why does an inspector keep horizontal items on iPhone Duo?
The detail column already has a vertical bar, and a second one next to it would compete with it. Apple chose not to give expanded inspectors their own vertical bar, so their items stay horizontal.
How do I keep tabs visible when the vertical bar runs out of room?
Apply toolbarVerticalCompressionBehavior(.prefersTabBar) in SwiftUI or set verticalBarCompressionBehavior to .prefersTabBar on the navigation item in UIKit. By default, the toolbar compresses first so primary destinations stay accessible.
Can I show a sidebar instead of a tab bar on the iPhone Duo inner display?
Yes. In SwiftUI, use the sidebarAdaptable tab view style with defaultTabBarPlacement(.sidebar). In UIKit, set the tab bar controller's sidebar preferredPlacement to .sidebar. Both are available from iOS 27.0.
Sources
- Raise the bar with iPhone Duo · Apple Developer
- Prepare your app for iPhone Duo · Apple Developer
- Strike a pose with adaptive layouts on iPhone Duo · Apple Developer
- toolbarVerticalCompressionBehavior(_:) · Apple Developer Documentation
- verticalBarCompressionBehavior · Apple Developer Documentation
- toolbarVerticalBehavior(_:) · Apple Developer Documentation
- defaultTabBarPlacement(_:) · Apple Developer Documentation
- UITabBarController.Sidebar preferredPlacement · Apple Developer Documentation
- inspector(isPresented:content:) · Apple Developer Documentation
- layoutMarginsGuide · Apple Developer Documentation
- A Summary of the iPhone Duo Group Lab · Apple Developer Forums
- Tab bars move to the side on iPhone Duo too · @sarunw on X
- Items with an icon move to the vertical bar; text-only items stay horizontal · @sarunw on X
- A bar only goes vertical when its container sits along the display edge · @sarunw on X
- An expanded inspector keeps its items horizontal · @sarunw on X
- Size classes of each column in NavigationSplitView on iPhone Duo · @sarunw on X
- Set .visibilityPriority(.high) for important items · @sarunw on X
- Don't assume padding; use layoutMarginsGuide · @sarunw on X
- What can the APIs added in iOS 27.1 for iPhone Duo do? · DevelopersIO (Classmethod)
Make the fold part of your app.
We showcase apps and games that do something real with iPhone Duo. Send us yours with a link to it on the App Store, or see what other developers have built.