TechnologiesSwiftUI

NavigationSplitView struct

iOSmacOStvOSwatchOSvisionOSiOS 16.0+✓ renders

A view that presents views in two or three columns, where selections in

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.

  1. Declare the columns with the sidebar/detail initializer

    The two-column form takes a sidebar view builder and a trailing detail: closure, each describing one column of the interface. Here the leading closure holds the List of folders and the detail: closure holds the view that responds to the current pick — keeping selection on the left and presentation on the right.

  2. 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 List is given selection: $selection, bound to an @State property selection, so tapping a row updates the value that the detail: closure reads to decide what to render.

  3. 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 selection to show Text("\(selection) contents"), and falls back to a Text("Select a folder") placeholder when selection is nil — exactly the state the split view starts in or returns to.

  4. Style each column with standard navigation modifiers

    Views placed inside a NavigationSplitView column participate in navigation, so the usual modifiers apply per column. The sidebar's List carries .navigationTitle("Mailboxes") to title that column, and the detail content uses ordinary layout modifiers like .font(.title2) and .padding().

Try it — Change the 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.

NavigationSplitView.swift
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()
            }
        }
    }
}
Live preview
folder Inbox contents
folder Inbox contents
swift → lexer → parser → sema → uiir → canvas Open in Studio ↗
What's new in SwiftUI 27 →