Flutter web: Navigating URLs using named routes
👉 Update: Flutter’s new Navigation and Routing system is now available, and it is the preferred way to handle URLs in Flutter.
Named routes can be used to navigate between pages inside a Flutter mobile app, but they also work for URLs in Flutter web apps. This article explains how to add named routes to your app, and how you can customize them, to have pattern matching inside the routes.
Defining named routes
Named routes can be added to your application by defining them within the MaterialApp
class. The MaterialApp.routes
property contains a map listing each named route and its associated display widget. The MaterialApp.initialRoute
property determines what route displays as the application starts. The initialRoute
thus needs to be defined inside of the routes
property. For example:
A good practice to keep your code organized is to put named routes inside static variables, for example, on the widgets themselves:
Next, refactor MaterialApp.routes
with the named routes now defined as static variables:
Navigating between pages
To navigate from one page to another, simply push the named route to the navigator:
See a full interactive example of this on DartPad. If you build and run the application yourself for the web, you can also just type in /#/overview
inside the web browser. This pushes the route named overview to the Navigator
, and takes you to the OverviewPage
widget, as you can see in the following GIF:
Routing logic for dynamic URLs
You may need to address more complex scenarios then addressed here, such as having pattern matching inside the routes to allow for dynamic URLs. To extend this example, assume that you have many different articles on the overview page. For each article you want to be able to navigate directly via URLs:
/#/article/a-very-interesting-article
/#/article/newsworthy-news
To define named routes for all of the articles within the MaterialApp
does not scale very well. For such dynamic cases you need to do something more custom. As of this writing, the stable channel of Flutter is at v1.12, and there is no simple way to do this, though there are plans to add support for more advanced routing with the new Navigator.
For now you can use an external package, for example the Fluro package provides more advanced routing. It gives you wildcard pattern matching in routes, as well as parsing for query strings in URLs. There are probably many other available packages, so please leave a comment with the name of your favorite.
If you are up for the challenge, you can also get dynamic routes by making use of the MaterialApp.onGenerateRoute
property. Use this to write routing logic for when a named route is not inside of MaterialApp.routes
.
For each route, define a Path
with a RegEx
pattern. If the named route matches the pattern, return the associated widget. Next, define the Path
class to support that:
For the overview page and the home route, it is quite simple and looks similar to what you had before. The following example creates a RegEx
pattern that matches a slug (lowercase letters with a dash) that is used to find the corresponding article:
All that remains is to create an onGenerateRoute
function for MaterialApp
. If the current named route (settings.name
) is defined in the paths list, return the associated widget. Make sure to pass any named matches in the RegEx
(in this example it is the slug). If no matches are found, simply return null, WidgetsApp.onUnknownRoute
is called to handle such cases:
Make sure to define the onGenerateRoute
function inside the MaterialApp
class; you have implemented dynamic URLs with Flutter, using named routes! You can see a full interactive example on DartPad.
Conclusion
Whether you choose to write your own custom logic for routes, or simply use the routes support that exists within MaterialApp
, you get URL support by default with a Flutter app on the web, when using named routes. Implementing named routes can also ensure that you decouple the presentation logic from the routing logic, which leads to less code duplication.
Let me know in the comments what solution you use in your app, whether it is writing your own custom logic or using an external package.
Happy hacking!