Rene GensAuthorBlogGitHubLinkedIn

SwiftUI NavigationStack gotchas

20 February, 2024

Working on an iOS app with SwiftUI and ran into navigation issues. NavigationStack replaced NavigationView, but the API is different.

With NavigationStack, you use navigationDestination instead of NavigationLink with a destination:

NavigationStack {
    List(users) { user in
        NavigationLink(value: user) {
            UserRow(user: user)
        }
    }
    .navigationDestination(for: User.self) { user in
        UserDetailView(user: user)
    }
}

But here's what confused me - if you want to programmatically navigate, you need to use a path binding:

@State private var path = NavigationPath()

NavigationStack(path: $path) {
    // Your content
}
.onAppear {
    path.append(user) // Navigate programmatically
}

Also, if you're using deep linking, NavigationStack handles it differently. You need to set the path from the URL:

.onOpenURL { url in
    if let userId = extractUserId(from: url) {
        path.append(userId)
    }
}

One gotcha - if you're passing complex objects through navigation, make sure they conform to Hashable. NavigationStack uses the value for routing, so it needs to be hashable.

And if you need to pop to root or pop multiple screens, you manipulate the path array directly. It's more flexible than the old NavigationView, but also more manual.

Thanks for reading! Check out more posts on the blog if you'd like.

© 2025, Built with Gatsby