← All courses

Navigation & Passing Data

🗓 May 31, 2026 ⏱ 2 min read

NavigationStack: the modern navigation

To move between screens, wrap your content in a NavigationStack (iOS 16+, the replacement for the older NavigationView). It manages a stack of screens with an automatic back button and title bar.

NavigationStack {
    List(users) { user in
        NavigationLink(user.name) {
            ProfileView(user: user)     // the destination screen
        }
    }
    .navigationTitle("Users")
}

A NavigationLink shows a tappable row and pushes its destination when tapped — passing the data (user) is as simple as using it in the destination.

Programmatic navigation

Sometimes you navigate from code (after a login succeeds, say) rather than a tap. You drive this with a path you control:

struct AppView: View {
    @State private var path = NavigationPath()
    var body: some View {
        NavigationStack(path: $path) {
            Button("Go to settings") {
                path.append("settings")     // push programmatically
            }
            .navigationDestination(for: String.self) { route in
                if route == "settings" { SettingsView() }
            }
        }
    }
}

Value-based navigation

The modern style attaches a value to a link and declares how to render each type of value with navigationDestination(for:). This decouples the link from the destination and scales well in larger apps.

List(users) { user in
    NavigationLink(user.name, value: user)
}
.navigationDestination(for: User.self) { user in
    ProfileView(user: user)
}

Sheets and full-screen covers

Not every screen should push. Modal presentations (a compose form, a login) slide up over the current screen:

@State private var showSheet = false

Button("Compose") { showSheet = true }
    .sheet(isPresented: $showSheet) {
        ComposeView()
    }

Common mistakes

  • Forgetting the NavigationStack wrapper (links do nothing).
  • Still using the deprecated NavigationView for new apps.
  • Putting a navigation title on the stack instead of on the content inside it.
Summary: Wrap screens in a NavigationStack, push with NavigationLink (passing data by simply using it in the destination), navigate from code with a NavigationPath, and use .sheet for modal screens.