Navigation

iOS 16.4+iPadOS 16.4+

Moves through a hierarchy of screens with SwiftUI's native navigation stack.

Navigation stack with a large title and a list of projects
import SwiftUIstruct NavigationUsageExample: View {    struct Project: Identifiable, Hashable {        let id: String        let systemImage: String        let owner: String    }    private let projects = [        Project(id: "Launch plan", systemImage: "checklist", owner: "Ana Souza"),        Project(id: "Build 42", systemImage: "hammer", owner: "Bruno Lima"),        Project(id: "Q3 roadmap", systemImage: "map", owner: "Carla Dias"),        Project(id: "Staging keys", systemImage: "key", owner: "Diego Alves")    ]    var body: some View {        NavigationStack {            List(projects) { project in                NavigationLink(value: project) {                    Label(project.id, systemImage: project.systemImage)                }            }            .listStyle(.plain)            .navigationTitle("Projects")            .navigationDestination(for: Project.self) { project in                detail(for: project)            }        }    }    private func detail(for project: Project) -> some View {        List {            LabeledContent("Owner", value: project.owner)            LabeledContent("Status", value: "In progress")        }        .listStyle(.plain)        .navigationTitle(project.id)        .navigationBarTitleDisplayMode(.inline)    }}

Usage

The native NavigationStack already brings the Liquid Glass navigation bar, the back button, the swipe back gesture, and accessibility, so use it directly:

NavigationStack {    List(projects) { project in        NavigationLink(value: project) {            Label(project.name, systemImage: project.systemImage)        }    }    .navigationTitle("Projects")    .navigationDestination(for: Project.self) { project in        ProjectView(project: project)    }}

NavigationLink(value:) pushes the screen that .navigationDestination(for:) returns for that value. Put the destination on the stack's content, outside the list rows.

NavigationView is deprecated. Use NavigationStack instead, or NavigationSplitView for columns.

Push a screen to show more about the item people chose. For a separate task, like creating an item, present a Sheet instead. In a Tab View, give each tab its own stack.

On iPad, prefer a tab view for your app's sections, and use .tabViewStyle(.sidebarAdaptable) when they need a sidebar. NavigationSplitView shows columns on iPad and collapses into a single stack on iPhone.

Examples

Bind an array to NavigationStack(path:). Appending a value pushes its screen, and removing values goes back. Every pushed screen gets a back button.

Pushed project screen with a back button and an inline title
import SwiftUIstruct NavigationPathExample: View {    struct Project: Identifiable, Hashable {        let id: String        let systemImage: String        let owner: String    }    private let projects = [        Project(id: "Launch plan", systemImage: "checklist", owner: "Ana Souza"),        Project(id: "Build 42", systemImage: "hammer", owner: "Bruno Lima"),        Project(id: "Q3 roadmap", systemImage: "map", owner: "Carla Dias"),        Project(id: "Staging keys", systemImage: "key", owner: "Diego Alves")    ]    @State private var path: [Project] = []    var body: some View {        NavigationStack(path: $path) {            List(projects) { project in                NavigationLink(value: project) {                    Label(project.id, systemImage: project.systemImage)                }            }            .listStyle(.plain)            .navigationTitle("Projects")            .navigationDestination(for: Project.self) { project in                detail(for: project)            }        }    }    private func detail(for project: Project) -> some View {        List {            LabeledContent("Owner", value: project.owner)            LabeledContent("Status", value: "In progress")            Button("Back to projects") {                path.removeAll()            }        }        .listStyle(.plain)        .navigationTitle(project.id)        .navigationBarTitleDisplayMode(.inline)    }}

Subtitle

On iOS 26 and later, .navigationSubtitle(_:) adds a line of context under the title.

Large title with a subtitle above a list of projects
import SwiftUI@available(iOS 26.0, *)struct NavigationSubtitleExample: View {    struct Project: Identifiable, Hashable {        let id: String        let systemImage: String    }    private let projects = [        Project(id: "Launch plan", systemImage: "checklist"),        Project(id: "Build 42", systemImage: "hammer"),        Project(id: "Q3 roadmap", systemImage: "map"),        Project(id: "Staging keys", systemImage: "key")    ]    var body: some View {        NavigationStack {            List(projects) { project in                NavigationLink(value: project) {                    Label(project.id, systemImage: project.systemImage)                }            }            .listStyle(.plain)            .navigationTitle("Projects")            .navigationSubtitle("4 in progress")            .navigationDestination(for: Project.self) { project in                Text(project.id)                    .navigationTitle(project.id)            }        }    }}

Title

A large title helps people stay oriented. It moves into the bar as people scroll and comes back when they scroll to the top. To keep a screen's title small, use .navigationBarTitleDisplayMode(.inline), as the pushed screens in the examples do.

Keep titles under 15 characters, so they leave room for the back button and toolbar items.

Toolbar

To add actions to the navigation bar, use .toolbar(content:) with a plain Button or Menu, with no style. The system applies Liquid Glass, and items in the same ToolbarItemGroup share one background.

Navigation bar with sort and new project buttons next to the large title
import SwiftUIstruct NavigationToolbarExample: View {    enum SortOrder: Hashable {        case name        case owner    }    struct Project: Identifiable, Hashable {        let id: String        let systemImage: String    }    private let projects = [        Project(id: "Launch plan", systemImage: "checklist"),        Project(id: "Build 42", systemImage: "hammer"),        Project(id: "Q3 roadmap", systemImage: "map"),        Project(id: "Staging keys", systemImage: "key")    ]    @State private var sortOrder = SortOrder.name    var body: some View {        NavigationStack {            List(projects) { project in                NavigationLink(value: project) {                    Label(project.id, systemImage: project.systemImage)                }            }            .listStyle(.plain)            .navigationTitle("Projects")            .navigationDestination(for: Project.self) { project in                Text(project.id)                    .navigationTitle(project.id)            }            .toolbar {                ToolbarItemGroup(placement: .primaryAction) {                    Menu("Sort", systemImage: "arrow.up.arrow.down") {                        Picker("Sort", selection: $sortOrder) {                            Text("Name").tag(SortOrder.name)                            Text("Owner").tag(SortOrder.owner)                        }                    }                    Button("New Project", systemImage: "plus") {}                }            }        }    }}

For more on toolbar buttons and menus, see Button and Menu. For every placement, see the Apple documentation.

Color

The title, the back button, and the chevrons of navigation links use system colors, which keep their contrast on Liquid Glass, so FLX leaves them as they are. Symbols in your rows, like a Label's icon, use the theme's tint, which .flxTheme(_:) applies at the root of your app.

A plain list draws the system background. To show the theme's background instead, see List.

For more information, see the Human Interface Guidelines for toolbars and the Apple documentation.