Building a NavigationStack-Like SwiftUI Navigation Layer for Lower iOS Versions
Article Summary
Gishantha Darshana from PickMe Engineering built a NavigationStack-style router that works on iOS 15. No more hidden NavigationLinks cluttering your SwiftUI views.
SwiftUI's NavigationStack (iOS 16+) brought clean, state-driven navigation to Apple's framework. But teams supporting iOS 15 are stuck with the old NavigationLink approach, which tangles navigation logic into view code. This article breaks down a custom routing package that brings NavigationStack's mental model to lower deployment targets.
Key Takeaways
- Route-driven navigation separates flow state from view presentation logic
- Custom router subclasses enable feature-specific navigation patterns like popTo
- Stack-based architecture makes navigation testable without launching UI
- Open-source SwiftyRouter package supports iOS 15 with familiar push/pop API
A NavigationStack-like routing layer gives iOS 15+ apps clean MVVM navigation without binding state directly into SwiftUI views.
About This Article
SwiftUI's NavigationLink makes you put navigation state into views as @State or @Published booleans. This couples your presentation layer tightly to navigation logic, which gets messy fast when you're building MVVM apps with deep flows that need multiple hidden links.
Gishantha Darshana's VerticalNavigationRouter splits navigation into three parts. VerticalNavigationRouter holds the stack state, VerticalNavigationSession wraps routes with stable UUIDs, and VerticalNavigationHost renders destinations from the route stack without putting navigation bindings in your view bodies.
The SwiftyRouter package lets teams work with navigation as testable state. You can validate it without running the UI. Unit tests can check stack behavior with simple assertions, like verifying router.stack.map(\.route) == [.details] after a push operation.