SwiftUI Navigation: NavigationStack Patterns

NavigationStack replaced NavigationView in iOS 16. Here are the patterns that work for real apps.

Key Insights

  • NavigationStack with NavigationPath gives you programmatic control over the navigation stack
  • Type-safe navigation destinations replace stringly-typed approaches
  • Deep linking becomes trivial when navigation state is data-driven

Basic NavigationStack

struct ContentView: View {
    @State private var path = NavigationPath()

    var body: some View {
        NavigationStack(path: $path) {
            List(items) { item in
                NavigationLink(value: item) {
                    Text(item.title)
                }
            }
            .navigationDestination(for: Item.self) { item in
                DetailView(item: item)
            }
        }
    }
}

Programmatic Navigation

// Push a view
path.append(someItem)

// Pop to root
path = NavigationPath()

// Pop one level
path.removeLast()

Deep Linking

Since the path is just data, restoring state from a URL is straightforward:

func handle(url: URL) {
    let components = url.pathComponents
    path = NavigationPath()
    for component in components {
        if let item = resolveItem(component) {
            path.append(item)
        }
    }
}

Liked this? There's more.

Every week: one practical technique, explained simply, with code you can use immediately.