iOS Navigation Series: Programmatic Navigation with SwiftUI
- Eric Palma
- Oct 22, 2023
- 6 min read
Updated: Mar 26
So far we have relied on the SwiftUI navigation APIs to handle navigation between our screens in both our NavigationStacks and TabViews in response to user input.
However, when facing complex navigation hierarchies and requirements, it can become necessary for us to take on the responsibility of managing our navigation programmatically. In this post we will learn the ways SwiftUI allows us to perform programmatic navigation in both NavigationStack and TabView.
What’s Covered:
Programmatic Control of NavigationStack:
How to manage navigation hierarchies using single data type paths or NavigationPath for multiple types.
Techniques to observe and manipulate the navigation stack dynamically.
Advanced TabView Management:
Control tab navigation programmatically using a selection binding.
Enable advanced features like pop-to-root when reselecting the current tab.
Real-World Applications: Learn how to implement practical features like tracking user navigation and adding shortcuts to streamline the user experience.
What You’ll Gain:
A deeper understanding of SwiftUI navigation mechanics, including programmatic techniques for both NavigationStack and TabView.
Code examples that demonstrate step-by-step solutions to navigate complex hierarchies.
Tips for enhancing UX with features like popping to root and dynamic tab control.
I highly recommend you check out our previous posts in the series:
Programmatically controlling NavigationStack
Starting with iOS 16, when we declare our NavigationStack, we have two initializers available to us, each taking a binding to a path variable. The first initializer accepts a collection of a single data type, and the second accepts a type-erased collection type called NavigationPath.
Both of these collections represent the current state of our navigation stack, allowing us to both observe and modify it programmatically. To see how the path variable corresponds to our stack, let’s take a look at a depiction:

Notice how the root screen is not added to our path collection, instead, only the screens added on top of the root screen in the navigation stack are appended. If our path variable is empty, that means we are only displaying the root screen. Alternatively, if it is not empty, any screens contained in the collection are screens added to our stack hierarchy, with the last element representing the top of stack (our currently visible screen).
Programmatic navigation using single data type path
When we only have a single data type associated with a navigation destination, we can make use of the first initializer provided for NavigationStack.
Here we use a State property called presentedArticles to manage the state of our navigation stack.
Pass Binding to presentedArticles as the path argument for our NavigationStack's initializer.
Now, we can use the reference to our presentedArticles variable to control navigation as needed. For example, we can use it to quickly pop back to our root view:
We could even use it to add multiple views at once, allowing us to rapidly navigate deep into our view hierarchy:
Join my newsletter for iOS development insights, tips, and a 25% discount on any subscription plan!
Want to read more?
Subscribe to curiousalgorithm.com to keep reading this exclusive post.