How to Add Navigation in SwiftUI

Use SwiftUI navigation when your app needs screen-to-screen flows, drill-down detail pages, settings stacks, or tab-based content hierarchies. The modern default is NavigationStack.

What you’ll build or solve

You’ll learn how to add navigation in SwiftUI with NavigationStack, NavigationLink, and destination views. You’ll also know when modal presentation is a better choice.

When this approach works best

This approach is the right choice when users should move deeper through hierarchical screens.

Common real-world scenarios include:

  • Settings flows
  • Product details
  • Lesson drill-down
  • Profile editing
  • Admin tools

This is a bad idea when the next screen should be temporary and dismissible, where sheets are clearer.

Prerequisites

You only need:

  • Basic SwiftUI views
  • Multiple screens
  • Familiarity with View structs

Step-by-step instructions

Step 1: Wrap the root view in NavigationStack

Start with a navigation container.

import SwiftUI

struct HomeView: View {
    var body: some View {
        NavigationStack {
            Text("Home")
        }
    }
}

This enables push-based navigation.

Step 2: Add a NavigationLink

Use links to move to another screen.

struct HomeView: View {
    var body: some View {
        NavigationStack {
            NavigationLink("Go to Profile") {
                ProfileView()
            }
        }
    }
}

struct ProfileView: View {
    var body: some View {
        Text("Profile")
    }
}

This pushes the destination onto the navigation stack.

Step 3: Use navigation titles

Titles improve orientation.

NavigationStack {
    NavigationLink("Settings") {
        SettingsView()
    }
    .navigationTitle("Home")
}

This gives the screen a clear native header.

What to look for:

  • NavigationStack is the modern default
  • NavigationLink pushes screens
  • Great for hierarchical flows
  • Titles improve orientation
  • Use sheets for temporary flows

Examples you can copy

Basic push

NavigationLink("Open") {
    DetailView()
}

Settings route

NavigationLink("Billing") {
    BillingView()
}

Title

.navigationTitle("Courses")

Common mistakes and how to fix them

Mistake 1: Missing NavigationStack

What the reader might do:

Use NavigationLink directly.

Why it breaks: navigation behavior becomes incomplete.

Corrected approach:

Wrap the root in NavigationStack.

Mistake 2: Using navigation for temporary modals

What the reader might do:

Push screens for quick confirmations.

Why it breaks: modal UX is clearer.

Corrected approach:

Use .sheet().

Mistake 3: Deep unclear hierarchies

What the reader might do:

Create many unclear nested routes.

Why it breaks: users lose context.

Corrected approach:

Use clear titles and predictable flow.

Troubleshooting

If the push does not happen, verify NavigationStack.

If the flow should dismiss instead of stack, switch to sheets.

If the title is missing, apply .navigationTitle() inside the stack.

If stateful paths are needed, use programmatic navigation with NavigationPath.

Quick recap

  • Use NavigationStack for screen flows
  • Use NavigationLink to push destinations
  • Add navigation titles
  • Great for drill-down hierarchies
  • Use sheets for temporary screens