Skip to content

Mastering NavigationSplitView (SwiftUI)

A SwiftUI guide for coding agents. Also covers sidebar detail layout ipad, three column navigation, column visibility binding, selection based list navigation, split view column width.

NavigationSplitView (iOS 16) builds two- and three-column apps: sidebar, optional content list, and detail. Place it at the root of the scene; each column's root is wrapped in its own NavigationStack automatically.

Selection Drives the Columns

Pair value-based NavigationLinks with selection-based Lists. Pressing a link assigns its value to the list's selection binding, and the next column reads that selection.

NavigationSplitView {
  List(selection: $selectedFolder) {
    ForEach(Array(folders.keys.sorted()), id: \.self) { folder in
      NavigationLink(value: folder) { Text(verbatim: folder) }
    }
  }
  .navigationTitle("Sidebar")
} content: {
  if let selectedFolder {
    List(selection: $selectedItem) {
      ForEach(folders[selectedFolder, default: []], id: \.self) { item in
        NavigationLink(value: item) { Text(verbatim: item) }
      }
    }
  } else {
    Text("Choose a folder from the sidebar")
  }
} detail: {
  if let selectedItem {
    Text(verbatim: selectedItem)
  } else {
    Text("Choose an item from the content")
  }
}

A NavigationLink outside a selection-based list needs its own NavigationStack with a navigationDestination in that column, the pattern for push navigation inside the detail pane.

A navigationDestination outside any NavigationStack navigates in the next column of the split view. The same modifier inside a NavigationStack pushes onto that stack instead. Placement is the whole behavior switch.

Visibility, Style, and Width

Bind columnVisibility to change columns programmatically, for example a Focus button that hides everything but the detail.

NavigationSplitView(columnVisibility: $visibility) { /* ... */ }

Button("Focus") { visibility = .detailOnly }

NavigationSplitViewVisibility offers automatic, all, doubleColumn, and detailOnly. The style modifier picks how columns share space: balanced shrinks the detail to keep the first two columns visible, prominentDetail keeps the detail large.

.navigationSplitViewStyle(.balanced)

Fix a column's width with navigationSplitViewColumnWidth on that column's root view.

} content: {
  ContentList()
    .navigationSplitViewColumnWidth(300)
}

Use this guidance in your coding agent

Install the Better Design MCP once. Your agent then loads this page with one call.

get-swiftui-guide({ topic: "swiftui-mastering-navigationsplitview" })
claude mcp add --scope user better-design --transport http https://better-design.com/api/mcp --header "Authorization: Bearer <YOUR_API_KEY>"
Browse related design systems