How it works
A NavigationSplitView presents a multicolumn navigation interface, pairing a sidebar of choices with the content those choices reveal. Use it when your app's data has a clear hierarchy that benefits from showing the levels side by side rather than one screen at a time — mailboxes alongside their messages, or categories alongside their items. On wide displays the columns appear together; on compact widths SwiftUI automatically collapses them into a stack-style push-and-pop flow, so a single declaration adapts to iPhone, iPad, and Mac. Reach for it instead of NavigationStack whenever a persistent sidebar makes the structure clearer.
Declare the columns with the sidebar/detail initializer
The two-column form takes a
sidebarview builder and a trailingdetail:closure, each describing one column of the interface. Here the leading closure holds theListof folders and thedetail:closure holds the view that responds to the current pick — keeping selection on the left and presentation on the right.Drive the detail column from a selection binding
The split view shows its detail by reacting to selected state rather than by you pushing views. The
Listis givenselection: $selection, bound to an@Statepropertyselection, so tapping a row updates the value that thedetail:closure reads to decide what to render.Handle the empty selection in the detail closure
Because a column can have nothing chosen, the detail builder must account for the no-selection case. The example unwraps with
if let selectionto showText("\(selection) contents"), and falls back to aText("Select a folder")placeholder whenselectionis nil — exactly the state the split view starts in or returns to.Style each column with standard navigation modifiers
Views placed inside a
NavigationSplitViewcolumn participate in navigation, so the usual modifiers apply per column. The sidebar'sListcarries.navigationTitle("Mailboxes")to title that column, and the detail content uses ordinary layout modifiers like.font(.title2)and.padding().
selection initial value from "Inbox" to nil and run it — the detail column opens on the Text("Select a folder") placeholder, showing how NavigationSplitView reflects the empty-selection state.Example & preview
Press Run live & edit to compile it in your browser — then edit the Swift on the left and the preview re-renders live.
struct NavigationSplitViewDemo: View {
@State private var selection: String? = "Inbox"
private let folders = ["Inbox", "Sent", "Drafts"]
var body: some View {
NavigationSplitView {
List(folders, id: \.self, selection: $selection) { folder in
Label(folder, systemImage: "folder")
}
.navigationTitle("Mailboxes")
} detail: {
if let selection {
Text("\(selection) contents")
.font(.title2)
.padding()
} else {
Text("Select a folder")
.foregroundStyle(.secondary)
.padding()
}
}
}
}