Logo for tanaschita.com

How to use NavigationPath for routing in SwiftUI

Learn how to manage navigation in SwiftUI programmatically.

09 Jun 2024 · 5 min read

With NavigationPath, SwiftUI provides a robust and flexible way to handle navigation and routing. It allows us to programmatically control the navigation stack without the need to use a NavigationLink.

In this article, we'll explore how to use NavigationPath in a practical example.

Let's jump in.

Sponsorship logo
Preparing for a technical iOS job interview - updated for iOS 18
Check out my book on preparing for a technical iOS job interview with over 200 questions & answers. Test your knowledge on iOS topics such as Swift, SwiftUI, Combine, HTTP Networking, Authentication, SwiftData & Core Data, Concurrency with async/await, Security, Automated Testing, Machine Learning and more.
LEARN MORE

When creating a NavigationStack, we have the possibility to pass in a path parameter:

struct SomeView: View {
@State private var navigationPath = NavigationPath()
var body: some View {
NavigationStack(path: $navigationPath) {
...
}
}
}

The passed in path is a Binding to the navigation state for this stack - enabling us to control the navigation stack by appending data to it:

navigationPath.append(route)

Let's say, we are building an app which can navigate to a recipes search - which in turn can navigate to a recipe detail when a user selects one of the results.

The approach to control this flow could look as follows:

1. Defining an enum which represents all possible navigation routes

enum Route: Hashable {
case recipesSearch
case recipeDetail(recipe: Recipe)
}

We don't explicitly need it to use NavigationPath, but I personally find it really helpful to have explicitly defined navigation routes.

2. Creating an Observable router which holds the navigation path

To be able to access the same navigation path from different views, we create a router as an Observable which holds the reference to the navigation path and provides a utility function for navigation:

@Observable
class Router {
var navigationPath = NavigationPath()
func navigateTo(route: Route) {
navigationPath.append(route)
}
}

3. Passing in the router as an environment object to all subviews

For a subview to be able to access and use our created router, we pass it in as an environment object:

struct MainView: View {
@State private var router = RecipesRouter()
var body: some View {
NavigationStack(path: $router.navigationPath) {
RecipesFeedView()
.environment(router)
}
}
}

4. Defining a navigation destination for possible routes

As a next step, we define a navigationDestination for each of our routes by providing views a specific route should navigate to:

RecipesFeedView()
.environment(router)
.navigationDestination(for: RecipesRouter.Route.self) { route in
switch route {
case .recipesSearch:
RecipesSearchView()
.environment(router)
case .recipeDetail(let recipe):
RecipeDetailView(recipe: recipe)
.environment(router)
}
}

5. Using router where needed

Finally, we can use the router for navigation anywhere we need by accessing it tough the @Environment property wrapper:

struct RecipesFeedView: View {
@Environment(RecipesRouter.self) var router
var body: some View {
...
Button(action: {
router.navigateTo(route: .recipesSearch)
}, label: {
Image(systemName: "magnifyingglass")
})
}
}
Sponsorship logo
Preparing for a technical iOS job interview - updated for iOS 18
Check out my book on preparing for a technical iOS job interview with over 200 questions & answers. Test your knowledge on iOS topics such as Swift, SwiftUI, Combine, HTTP Networking, Authentication, SwiftData & Core Data, Concurrency with async/await, Security, Automated Testing, Machine Learning and more.
LEARN MORE

Newsletter

Image of a reading marmot
Subscribe

Like to support my work?

Say hi

Related tags

Articles with related topics

combine

swiftui

swift

ios

How to delay server requests for user's search query with SwiftUI and Combine

Learn how to debounce on a practical example.

15 Jul 2024 · 5 min read

Latest articles and tips

© 2024 tanaschita.com

Privacy policy

Impressum