SwiftUI Patterns

Value-Based NavigationLink

June 9, 2026
5 min read
Featured image for blog post: Value-Based NavigationLink

NavigationLink with values separates "what to navigate to" from "how to display it." Here's how it works.

Follow along with the code: iOS-Practice on GitHub

The Old Way (Deprecated)

// iOS 15 and earlier
NavigationLink(destination: UserDetailView(user: user)) {
    Text(user.name)
}

Problems:

  • Destination view created immediately
  • Hard to share navigation logic
  • No programmatic navigation

The New Way

// iOS 16+
NavigationLink(value: user) {
    Text(user.name)
}

The destination is defined separately:

.navigationDestination(for: User.self) { user in
    UserDetailView(user: user)
}

Complete Example

struct MasterView: View {
    let users: [User]

    var body: some View {
        List(users) { user in
            NavigationLink(value: user) {
                HStack {
                    Image(systemName: user.avatarURL)
                        .font(.title)
                    VStack(alignment: .leading) {
                        Text(user.name).font(.headline)
                        Text(user.company).font(.caption)
                    }
                }
            }
        }
        .navigationTitle("Users")
        .navigationDestination(for: User.self) { user in
            UserDetailView(user: user)
        }
    }
}

Multiple Destinations

Handle different types with multiple modifiers:

.navigationDestination(for: User.self) { user in
    UserDetailView(user: user)
}
.navigationDestination(for: Post.self) { post in
    PostDetailView(post: post)
}
.navigationDestination(for: Settings.self) { _ in
    SettingsView()
}

Programmatic Navigation

Control navigation with NavigationPath:

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

    var body: some View {
        NavigationStack(path: $path) {
            Button("Go to User") {
                path.append(someUser)
            }
            .navigationDestination(for: User.self) { user in
                UserDetailView(user: user)
            }
        }
    }

    func navigateToUser(_ user: User) {
        path.append(user)
    }

    func popToRoot() {
        path.removeLast(path.count)
    }
}

Hashable Requirement

Your model must conform to Hashable:

struct User: Identifiable, Hashable {
    let id: Int
    let name: String
    let email: String

    // Hashable is auto-synthesized for structs with Hashable properties
}

Benefits

  1. Lazy destination creation - Views created only when navigated
  2. Type safety - Compiler verifies navigation types
  3. Centralized logic - One place defines all destinations
  4. Deep linking - Easy to restore navigation state from URL

Interview Tip

This is the modern SwiftUI navigation pattern. Discuss how it enables programmatic navigation and deep linking.

Originally published on pixelper.com

© 2026 Christopher Moore / Dead Pixel Studio

Let's work together

Professional discovery, design, and complete technical coverage for your ideas

Get in touch