Flutter: GoRouter with ShellRoute

Flutter: GoRouter with ShellRoute

25-Jun-2024 - Sophoun

Hi, this is my third blog. This blog will explain to you how to use GoRouter with the ShellRoute in the Flutter application.

I think you already know about GoRouter but here I will guide you all the setup to the usage of GoRouter.

Introduction

GoRouter is a popular navigation library in the Flutter community. It provides us a way to handle navigation and Deeplink seamlessly. Without GoRouter you will have a hard time implementing navigation using the traditional named route of Scaffold or MaterialApp.

Here I will write about how to use ShellRoute only. If you're just starting with GoRouter I suggest heading to my previous blog that explains about it suppurate

https://blog.sophoun.com/flutter-routing-using-gorouter

Ok, let's get into it in detail.

ShellRoute

ShellRoute is a way that you have sub-navigation in your application like when you want to have a bottom navigation bar or sidebar for the web.

Imagine you have a login screen for your users and after they log in to the app they will see a sidebar of functionality and they can move around with those and the selection state still be in the right place.

The scenario above isn't easy if you don't apply ShellRoute. Ok, let's apply coding.

Define ShellRoute

I assume you already have a GoRouter defined in your application. So below is how you define ShellRoute in Flutter.

Here is my router.dart file.

import 'package:go_router/go_router.dart'; import 'package:go_router_example/category_page.dart'; import 'package:go_router_example/dashboard_page.dart'; import 'package:go_router_example/home_page.dart'; import 'package:go_router_example/login_page.dart'; final goRouter = GoRouter( initialLocation: "/login", routes: [ GoRoute( path: '/login', builder: (context, state) => const LoginPage(), ), ShellRoute( builder: (context, state, child) => HomePage(child: child), routes: [ GoRoute( path: "/dashboard", builder: (context, state) => const DashboardPage(), ), GoRoute( path: "/category", builder: (context, state) => const CategoryPage(), ), ], ), ], );

As you see here, I define GoRouter and the initialize location is /login that points to the GoRoute path /login when the application starts.
I also have defined ShellRoute which has 2 children of GoRoute named /dashboard and /category . One thing the builder function of ShellRoute has a child that passes via parameter callback, it's a widget of its route that was navigated to. So this way you can design the sub-navigation as you wish in the HomePage.

Here is the code in my home_page.dart

import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; class HomePage extends StatefulWidget { const HomePage({ super.key, required this.child, }); final Widget child; State<HomePage> createState() => _HomePageState(); } class _HomePageState extends State<HomePage> { int selectedIndex = 0; Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("Home"), ), body: Row( children: [ NavigationRail( destinations: const [ NavigationRailDestination( icon: Icon(Icons.dashboard), label: Text("Dashboard"), ), NavigationRailDestination( icon: Icon(Icons.category), label: Text("Category"), ), ], selectedIndex: selectedIndex, labelType: NavigationRailLabelType.all, onDestinationSelected: (value) { selectedIndex = value; switch (value) { case 0: context.go("/dashboard"); break; case 1: context.go("/category"); break; default: throw Exception("Unknow destination"); } }, ), Expanded( child: widget.child, ) ], ), ); } }

Here I have defined a NavigationRail that has 2 destinations, one to /dashboard and one to /category.
I also have a child widget that accepts via constructor and places it as a child. This child widget is a widget that passes via ShellRoute when it navigates.

By defined the goRouter and HomePage I can customize the navigation and easy to navigate between those children easily.

Below is the code in my login_page.dart file

import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; class LoginPage extends StatefulWidget { const LoginPage({super.key}); State<LoginPage> createState() => _LoginPageState(); } class _LoginPageState extends State<LoginPage> { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("Login"), ), body: Center( child: FilledButton( onPressed: () { context.go("/dashboard"); }, child: const Text("Login"), ), ), ); } }

Here is the result and available code.

Result

Source code:
https://github.com/Sophoun/blogging_example/tree/main/flutter/go_router_example

That's all for today, if you have any questions or suggestions please comment.
Thank you for reading.