top of page

Routing library for SwiftUI Navigation

Writer's picture: Eric PalmaEric Palma

Updated: 2 days ago

At last, I have achieved a version of the Router pattern that I am happy with and addresses the problems I intended to solve when I started.


  • Remove navigation specific APIs from SwiftUI views.

  • Prevent views from knowing about other views and how to build them.

  • Shield views from knowing how other views are navigated to.


It is the result of all the exploratory work and iterations I made in previous posts:


Table of Contents

  1. Removing Navigation APIs from SwiftUI Views

    • Introducing the RoutingView as a wrapper.

    • Decoupling views from SwiftUI navigation APIs.

    • Injecting a Router instance into the view hierarchy.

  2. Moving Navigation Logic to the Router

    • How the Router manages navigation.

    • Simplifying view navigation with routeTo(_).

    • Programmatically manipulating the navigation stack.

  3. Achieving Modularity with the Routable Protocol

    • Defining navigation for modularized codebases.

    • Eliminating circular dependencies in the library.

    • Example implementation of the Routable protocol.

  4. Supporting Deeplinks in SwiftUI Routing

    • Adding support for deeplinks in a manner compatible with the SwiftUI Routing pattern.

  5. Next Steps and Community Contributions

    • Future plans for the library.

    • How to contribute or provide feedback.


You can find the open source repo for this library and contribute on my Github -> https://github.com/obvios/Routing

Removing navigation APIs from SwiftUI views


The first step was figuring out how to remove any SwiftUI navigation code out of my views. To solve this I created a RoutingView that acts as a wrapper for the view hierarchy.


It contains the SwiftUI navigation APIs for supporting stack navigation, sheet presentation, and full screen cover presentation.


Additionally, it is responsible for creating the Router instance that gets injected into the root view and is used to manage navigation within the RoutingView.

This RoutingView is only responsible for containing the SwiftUI navigation APIs and utilizing the Router object to build views.


Moving navigation logic to the Router


The Router object is responsible for acting as the gateway to navigation for individual views. It contains the @Publshed properties that the RoutingView observes to trigger the appropriate navigation action.


All views have to do is call the routeTo(_) method and the Router will do the rest. It hides how views are created and navigated to (ie: via navigation stack, sheet, full screen cover).


The object also provides other useful methods for manipulating the navigation stack and dismissing screens programmatically.

Modularity


Finally, the Routable protocol was created to allow implementers to handle specific view creation as well as declare how views should be navigated to. As a result, this removes the previous dependency the Router had on the view code, which existed because the Router had to know how to build views.


This would lead to a circular dependency where the Routing package would need to know about code outside of it, namely the views it would navigate to. With the introduction of the Routable protocol, the Routing library has no dependency on any outside code, making it perfect for modularized code bases. Below is the Routable protocol definition:

Here is an example of how client code can implement the Routable protocol to define what views are used and how they are navigated to:

Support for Deeplinks in SwiftUI Routing


A user of my SwiftUI Routing library made the excellent suggestion of adding support for deeplinks. So it is with great pleasure to announce that beginning in v1.2.0, deeplinks are supported.


Handling deeplinks with the Routing library is as simple as the following code:

Simply attach the onDeepLink() modifier to any view inside the RoutingView and provide both the Router instance and a closure to process the deeplink URL. From there, all that's left to do is return a Routable destination.


The library will take care to display the view however you specified in the Routable destination. Additionally, you don't need to worry about dismissing any sheets or full screen covers as they will be automatically dismissed to present the view you specify in the closure.


Conclusion


I have enjoyed building this little library and plan on continuing to improve it. If you have any suggestions for improvement or wish to contribute, please do not hesitate to do so by either contributing directly to the Github repository or by contacting me via my contact form.


If you enjoyed following along this journey, you can subscribe to my newsletter to get more insights into iOS development and be amongst the first to hear about my latest posts.

Comments


Site
Join the growing community of iOS engineers who are taking their skills to the next level.

© 2025 Curious Algorithm. All rights reserved.

bottom of page