How it works
NavigationPath is a type-erased container that holds the data identifying the views currently pushed onto a navigation stack. Reach for it when you want to drive a NavigationStack programmatically rather than relying solely on user taps: because it can store values of differing types in a single, observable collection, it lets you append, pop, and inspect the navigation history as ordinary state. Bind it to a NavigationStack to make the stack's contents something your code reads and mutates directly, which is the foundation for deep linking, restoring a saved location, or jumping back to the root in one call.
Hold the path as observable state
NavigationPath is a value type designed to live in your view's state so SwiftUI re-renders when the stack changes. Declare it with @State and its empty initializer, as in
@State private var path = NavigationPath(), which represents an empty stack showing only the root view.Bind it to the stack with NavigationStack(path:)
Passing a binding to the path makes the stack and the collection mirror each other: pushes you make in code appear on screen, and views the user pops are removed from the path. Here the binding
$pathis handed toNavigationStack(path: $path)so the structure becomes the single source of truth for what's presented.Push values with append
Calling append adds a value to the end of the path, which presents the destination registered for that value's type. The buttons push different items onto the same path via
path.append("Apple")andpath.append("Banana"), demonstrating how NavigationPath grows as a heterogeneous list of presented items.Resolve each entry with navigationDestination(for:)
A NavigationPath only stores data; the stack needs a destination builder to turn each stored value into a view. The
.navigationDestination(for: String.self)modifier matches the appendedStringvalues and supplies thefruitview for each one, so an appended value becomes a screen.Read and unwind the stack with count and removeLast
Because the path is a collection, you can query its depth and clear it. The title reads its length through
path.count, whilepath.removeLast(path.count)pops every entry at once to return to the root view, showing how NavigationPath supports inspecting and rewinding navigation in code.
path.removeLast(path.count) in the "Back to root" button with path.removeLast() to pop just one level and watch the difference between unwinding the whole stack and stepping back a single screen.Example & preview
Press Run live & edit to compile it in your browser — then edit the Swift on the left and the preview re-renders live.
struct NavigationPathDemo: View {
@State private var path = NavigationPath()
var body: some View {
NavigationStack(path: $path) {
List {
Button("Push Apple") { path.append("Apple") }
Button("Push Banana") { path.append("Banana") }
}
.navigationTitle("Fruits (\(path.count))")
.navigationDestination(for: String.self) { fruit in
VStack {
Text(fruit).font(.largeTitle)
Button("Back to root") { path.removeLast(path.count) }
}
.padding()
}
}
.padding()
}
}