Exploring the Navigation Split View

Exploring the Navigation Split View

Explore the NavigationSplitView on different platforms, how to use it and the related modifiers.

The NavigationSplitView is a user interface component that enables a sidebar-detail interface, where the primary view (sidebar) controls the content of the secondary view (detail). This design pattern is particularly effective for applications that manage a collection of items and need to display detailed information about a selected item.

The NavigationSplitView in the Contacts App in iPadOS

We can implement this type of navigation in our apps by using the NavigationSplitView container, that works exactly as the NavigationStack that we place at the root of our app to create navigation inside our app, to create multi-column interfaces.

The appearance across different OS

iPadOS

On iPadOS, the NavigationSplitView makes full use of the larger screen by occupying the entire display. Users can hide the sidebar by pressing the Sidebar button and bring it back by swiping from left to right for a quick view, or by pressing the button again to keep it fixed. This behavior remains consistent in both portrait and landscape modes.

The NavigationSplitView in the Mail App in iPadOS

macOS

On macOS, the NavigationSplitView integrates smoothly into the desktop environment with a translucent Sidebar, enhancing the contrast between the sidebar and the content.

The NavigationSplitView in the Maps App in MacOS

VisionOS

In visionOS, the NavigationSplitView combines elements of both macOS and iPadOS. The sidebar features a glass material that distinguishes the entire operating system. Additionally, visionOS allows combining the tab bar and sidebar, creating a more structured hierarchy for content.

The NavigationSplitView in the Photos App in visionOS

iOS

On iOS, the NavigationSplitView is optimized for larger devices like the iPhone Max models. In landscape mode, it prioritizes the detail section while maintaining access to the sidebar, making efficient use of the additional screen space. In portrait mode, the NavigationSplitView behaves like a NavigationStack, ensuring compatibility and ease of use across multiple platforms. This adaptability allows developers to support multi-platform navigation.

The NavigationSplitView in the Contacts App in iOS on an iPhone Pro Max

In portrait mode, the NavigationSplitView will function the same as the NavigationStack, making it easy for us to support multi-platform navigation.

The NavigationSplitView in the Contact App in iOS

How to use it

You can create a simple two-column layout using the NavigationSplitView container. You can achieve this by passing a List component for the sidebar section. Each element of the list will be a NavigationLink, which will display a new View in the detail section of the container.


import SwiftUI

struct ContentView: View {
    var body: some View {
        NavigationSplitView {
            List {
                NavigationLink("Item 1", destination: Text("Destination 1"))
                NavigationLink("Item 2", destination: Text("Destination 2"))
            }
            .navigationTitle("Sidebar")
        } detail: {
            ContentUnavailableView("Select an element from the sidebar", systemImage: "doc.text.image.fill")
        }
    }
}

As you can see, we need also to define the view that the user will see before selecting an item from the sidebar. In this case, we are using a ContentUnavailableView.

If you don't know what it is and how to use it, check out this article:

Display empty states with ContentUnavailableView in SwiftUI
Learn how to use the ContentUnavailableView to represent empty states in a SwiftUI application.

Three column layout

Using the init(sidebar:content:detail:) initializer, we can create a three-column layout. In this layout, selecting an item in the sidebar updates the content section, and selecting an item in the content section updates the detail section.


import SwiftUI

struct ContentView: View {

    @State private var visibility: NavigationSplitViewVisibility = .all
    
    var body: some View {
        NavigationSplitView(columnVisibility: $visibility) {
            List {
                NavigationLink("Category 1", destination: CategoryView(category: "Category 1"))
                NavigationLink("Category 2", destination: CategoryView(category: "Category 2"))
            }
            .navigationTitle("Sidebar")
        } content: {
            ContentUnavailableView("Select an element from the sidebar", systemImage: "doc.text.image.fill")
        } detail: {
            ContentUnavailableView("Select an element from the list", systemImage: "doc.text.image.fill")
        }
    }
}

struct CategoryView: View {
    let category: String

    var body: some View {
        List {
            NavigationLink("\\(category) Item 1", destination: DetailView(item: "\\(category) Item 1"))
            NavigationLink("\\(category) Item 2", destination: DetailView(item: "\\(category) Item 2"))
        }
        .navigationTitle("Content")
    }
}

struct DetailView: View {
    let item: String

    var body: some View {
        Text("Details for \\(item)")
            .navigationTitle("Detail")
    }
}

In this example, we also defined a property named visibility of type NavigationSplitViewVisibility to manage the visualization of each section of the NavigationSplitView container.

Modifier

To customize the appearance of the NavigationSplitView container, we can use modifiers to specify the dimensions of each section. There are two different modifiers available:

  1. The navigationSplitViewStyle(_:) modifier that has two options:
    • prominentDetail: Sets the detail section as the section with the highest priority. This means that the detail view will retain its full size at all times, and the sidebar and the content view will slide over the detail view.
    • balanced: Reduces the size of your detail view as the sidebar or content bar is shown.
  2. navigationSplitViewColumnWidth(_:): This allows us to assign a fixed size to each column of the NavigationSplitView container.

The NavigationSplitView in SwiftUI is a versatile and powerful container that enhances the navigation experience across various Apple operating systems. By leveraging the unique characteristics of each platform—whether it’s the full-screen utilization on iPadOS, the translucent sidebar on macOS, the glass material and hierarchical structure on visionOS, or the adaptive behavior on iOS —NavigationSplitView provides a consistent and intuitive user interface.