Skip to content
Prepare to Grow

SwiftUI Fundamentals

Navigation with NavigationStack

Build value-driven navigation with destinations, paths, deep-linkable state, and clear ownership of the navigation model.

Intermediate6 min read2 guided activities

Before you begin

What you will understand

  • Create value-based NavigationLink destinations.
  • Register destinations with navigationDestination.
  • Control a NavigationPath programmatically.
  • Model navigation as feature state without tightly coupling child views.
01

Learning stage

Concept Explanation

NavigationStack presents a root and a stack of pushed destinations. Value-based NavigationLink stores a Hashable value representing where the user wants to go. navigationDestination maps that value type to a destination view, separating navigation intent from destination construction.

A bound path makes the stack programmatically controllable. It can support deep links, restoration, multi-step flows, and returning to a known root. Prefer a typed array when one route enum represents all destinations; NavigationPath is useful when the path contains multiple unrelated Hashable types.

Navigation state needs an owner. A feature root may own a route array and pass action closures into children. Child rows should express user intent instead of reaching into a global router unnecessarily. Keep modal presentation separate from pushed path state unless the flow model deliberately unifies them.

  • NavigationStack: owns a hierarchical pushed interface.
  • NavigationLink(value:): expresses a destination value.
  • navigationDestination: maps a value type to a destination view.
  • Path: an ordered representation of pushed destinations.
  • Route enum: a typed model for the destinations a feature supports.
02

Learning stage

Syntax & Examples

A route enum creates one typed navigation vocabulary that supports links and programmatic path changes.

LearningNavigation.swiftswift
import SwiftUI

struct Lesson: Identifiable, Hashable {
  let id: UUID
  let title: String
}

enum LearningRoute: Hashable {
  case lesson(Lesson)
  case quiz(lessonID: Lesson.ID)
}

struct LearningRoot: View {
  let lessons: [Lesson]
  @State private var path: [LearningRoute] = []

  var body: some View {
    NavigationStack(path: $path) {
      List(lessons) { lesson in
        NavigationLink(lesson.title, value: LearningRoute.lesson(lesson))
      }
      .navigationTitle("Lessons")
      .navigationDestination(for: LearningRoute.self) { route in
        switch route {
        case .lesson(let lesson):
          LessonDetail(lesson: lesson) {
            path.append(.quiz(lessonID: lesson.id))
          }
        case .quiz(let lessonID):
          QuizScreen(lessonID: lessonID)
        }
      }
    }
  }
}
Navigation is data: links append typed route values, destinations interpret them, and the root can inspect or replace the path.
03

Learning stage

Real-World Usage

Connect the SwiftUI concept to complete, maintainable application features.

  • Navigate from collections into detail and editor screens.
  • Implement onboarding and multi-step flows.
  • Translate a deep link into a route path.
  • Restore a user's position when the route values are codable and appropriate to preserve.
04

Learning stage

Common Mistakes

Identify patterns that weaken ownership, identity, adaptation, accessibility, or user experience.

  • Using deprecated NavigationView patterns in new code.
  • Creating NavigationStack independently inside every destination.
  • Registering navigationDestination in a branch where the link cannot reach it.
  • Putting large mutable models directly into route identity.
  • Using a global router for a small self-contained feature without need.
05

Learning stage

Practice Exercises

Build the behavior in a small Xcode project and review it in multiple states.

Activity 1

Create typed feature routes

Build a route enum for course list, lesson detail, and quiz. Use a bound route array and navigate from detail to quiz programmatically.

Hint: Associated values should contain stable navigation inputs, not an entire service graph.

Activity 2

Translate a deep link

Given a lesson ID from a URL, validate it and construct the route path required to show its detail.

Hint: Invalid external input should result in a safe fallback, not an impossible route.

06

Learning stage

Knowledge Check

Answer each question before revealing the explanation.

QUESTION 1

What does navigationDestination(for:) do?

  1. A.Maps a navigation value type to its destination view
  2. B.Downloads route data
  3. C.Creates a tab bar
  4. D.Dismisses a sheet
Reveal answer

Maps a navigation value type to its destination view

A value-based link expresses the route value; the destination modifier defines how that type is presented.

QUESTION 2

Why bind a path to NavigationStack?

Reveal answer

To inspect and change the pushed navigation state programmatically.

A path enables deep links, restoration, flow resets, and explicit navigation actions.

07

Learning stage

Interview Preparation

Explain the design in terms of data flow, identity, lifecycle, platform behavior, and trade-offs.

Why prefer value-based navigation for a nontrivial SwiftUI feature?

Short answer: It makes navigation explicit state that can be tested, deep-linked, restored, and changed programmatically.

Explore the detailed answer

Views emit Hashable route values rather than constructing every destination inline. A feature root maps routes to screens and owns the path. This separates navigation intent, state, and destination building while keeping small local flows simple.

Possible follow-ups

  • • When would you use NavigationPath instead of a typed array?
  • • Who should own a feature's path?
08

Learning stage

Key Takeaways

Modern SwiftUI navigation is value driven. Model valid destinations explicitly, let a stable feature root own the path, and map route values to screens in one reachable navigation context.

  • NavigationStack replaces older NavigationView patterns.
  • NavigationLink can push Hashable values.
  • navigationDestination maps route data to UI.
  • A bound path enables programmatic flows and deep links.
  • Route ownership should match the feature boundary.