Skip to main content

How to create a two-column or three-column layout with NavigationSplitView

About 3 minSwiftSwiftUIArticle(s)bloghackingwithswift.comcrashcourseswiftswiftuixcodeappstore

How to create a two-column or three-column layout with NavigationSplitView 관련

SwiftUI by Example

Back to Home

How to create a two-column or three-column layout with NavigationSplitView | SwiftUI by Example

How to create a two-column or three-column layout with NavigationSplitView

Updated for Xcode 15

Updated in iOS 16

SwiftUI's NavigationSplitView allows us to create multi-column layouts on larger devices (iPadOS, macOS, and large iPhones in landscape), but automatically collapses to a NavigationStack-style layout when space is limited.

In its simplest form, you should provide your sidebar as its first trailing closure, and your detail view as its second, like this:

NavigationSplitView {
    Text("Sidebar")
} detail: {
    Text("Detail View")
}

Download this as an Xcode projectopen in new window

Usually, though, you'll want to add some kind of selection mechanism to the sidebar, then load that selection in the detail view, like this:

NavigationSplitView {
    List(1..<50) { i in
        NavigationLink("Row \(i)", value: i)
    }
    .navigationDestination(for: Int.self) {
        Text("Selected row \($0)")
    }
    .navigationTitle("Split View")
} detail: {
    Text("Please select a row")
}

Download this as an Xcode projectopen in new window

In that code, the “Please select a row” text is shown only when the user has yet to make a selection in the sidebar, but it will automatically be replaced when the user makes a selection - the navigationDestination() modifier displays its destination view in the detail area automatically. Even better, when space is limited you'll see the whole thing flattens down to a regular NavigationStack, so you get the best of both worlds.

If you want to go further, NavigationSplitView allows us to add a third view to its layout, which can be shown with a button tap:

struct ContentView: View {
    var body: some View {
        NavigationSplitView {
            Text("Sidebar")
        } content: {
            Text("Primary View")
        } detail: {
            Text("Detail View")
        }
    }
}

Download this as an Xcode projectopen in new window

SwiftUI will automatically take care of showing a button to slide in your bar from the side of the screen, and also collapse it with your primary view if you're in a compact size class.

If you're targeting iPadOS 15 or earlier, you can get a sidebar by placing three views inside a NavigationView, like this:

struct ContentView: View {
    var body: some View {
        NavigationView {
            Text("Sidebar")
            Text("Primary View")
            Text("Detail View")
        }
    }
}

Download this as an Xcode projectopen in new window

If you're presenting a list inside an iPadOS 15 sidebar, it's a good idea to use the .listStyle() to give it the system-standard theme for sidebars, like this:

struct ContentView: View {
    var body: some View {
        List(1..<100) { i in
            Text("Row \(i)")
        }
        .listStyle(.sidebar)
    }
}

Download this as an Xcode projectopen in new window

A list of rows with no separators and a gray background.
A list of rows with no separators and a gray background.
Similar solutions…
How to customize the display mode of NavigationSplitView | SwiftUI by Example

How to customize the display mode of NavigationSplitView
How to customize a view's width in NavigationSplitView | SwiftUI by Example

How to customize a view's width in NavigationSplitView
How to control which NavigationSplitView column is shown in compact layouts | SwiftUI by Example

How to control which NavigationSplitView column is shown in compact layouts
How to create a custom layout using the Layout protocol | SwiftUI by Example

How to create a custom layout using the Layout protocol
How to create an adaptive layout with ViewThatFits | SwiftUI by Example

How to create an adaptive layout with ViewThatFits

이찬희 (MarkiiimarK)
Never Stop Learning.