Skip to content

SwiftUI Navigation: Present Data, Not Views

Understanding the mental model shift from imperative navigation in UIKit to data-driven navigation in SwiftUI.

The Mental Model Shift

In UIKit, navigation is imperative. You tell the system exactly what to do:

let detailVC = DetailViewController()
detailVC.item = selectedItem
navigationController?.pushViewController(detailVC, animated: true)

You create a view controller, configure it, and push it onto the stack. You are in control of the action.

SwiftUI works differently. You do not navigate – you present data in new views. Everything is data-driven. You do not control views. You control data.

Data-Driven Navigation in Practice

With NavigationStack, navigation is driven by state. You declare what data maps to what view, and SwiftUI handles the transitions:

struct ContentView: View {
   @State private var path: [Item] = []

   var body: some View {
      NavigationStack(path: $path) {
         List(items) { item in
            Button(item.name) {
               path.append(item)  // Modify data, not views
            }
         }
         .navigationDestination(for: Item.self) { item in
            DetailView(item: item)
         }
      }
   }
}

The key line is path.append(item). You are not pushing a view. You are adding data to an array. SwiftUI observes the change and presents the corresponding view automatically.

Why This Matters

This distinction is not just philosophical – it has practical consequences. Because navigation is state, you get deep linking for free by constructing the right path array. You can persist and restore navigation state by saving the path. You can programmatically navigate to any depth by appending multiple items at once.

It also means dismissal is just data removal. Calling path.removeLast() pops the top view. Clearing the array returns to root. No need to track view controller references or walk the navigation hierarchy.

The shift takes time to internalize, especially if you have years of UIKit experience. But once it clicks, SwiftUI navigation becomes far more predictable. Your views become pure functions of your data, and navigation is just another piece of that data.

Found this helpful? Follow me on Bluesky and Mastodon for more Swift tips and indie dev updates.