Skip to main content

Material Design Navigation Bar in Flutter

After looking at the Tabs in Flutter, it's time for us to move on to the Flutter developer path. How to implement a navigation bar in Flutter? Do we know the difference between NavigationBar and BottomNavigationBar? Read on and I'll show you.

Flutter application with a BottomNavigationBar running on an Android device.

Note: The scope of this post is not to address third party dependencies that allow you to create custom navigation bars but the one included in the Flutter SDK which follows the Material Design style.

As was the case with the tabs. The navigation bars have evolved from Material Design 2 to Material Design 3.

Android mobile device showing the difference of a Flutter app with a navigation bar with Material Design 2 and Material Design 3.

BottomNavigationBar or NavigationBar?

You may have heard about both in Flutter. For the sake of clarity, BottomNavigationBar is an old-fashioned navigation bar that also looks like Material Design. Whereas a BottomNavigationBar looks with Material Design 2 a NavigationBar looks with Material Design 3.

Two iPhone 15 Pro running a Flutter app with BottomNavigationBar with Material Design 2 and Material Design 3.

That is why Google recommends in the BottomNavigationBar documentation that we migrate to NavigationBar as it is a reimplementation of it. So we will only find out about NavigationBar in this guide.

Implementing NavigationBar

For those who read the post where we saw how to work with Tabs you will see that they have many things in common. Google has done an excellent job of making the workflows similar.

Inside the view or screen to which we want to add the navigation bar, we go to the Scaffold widget, this has a property called bottomNavigationBar that will be our entry point. We will pass to this property a NavigationBar widget.

Dart code and documentation that displays the NavigationBar class in Flutter.

Looking at the documentation, we can draw three conclusions. 
  1. This widget cannot be marked as constant.
  2. The only required field is destinations
  3. The selectedIndex property must be a valid index and by defaults is the first one. 
If we look at what destinations are, we see that they are an array of NavigationDestination widgets.

Dart code and documentation of the destinations property of NavigationBar class

And what is a NavigationDestination? As we can see following the documentation. Each NavigationDestination object in the array defines each of the visual elements of the navigation bar.

Dart code that displays the NavigationDestination class in Flutter.

If we look at the required fields, we have (at a minimum) to pass the icon and label fields to define the icon and text respectively for this navigation element.

It is worth keeping an eye on all properties as we can do cool things like setting a different icon when that NavigationDestination is selected with the selectedIcon property. 

Dart code to create an array of NavigationDestination objects passed as a parameter to the destination of the NavigationBar class.

Now that we have our NavigationDestination widget array, let's create our NavigationBar as a property of the bottomNavigationBar of the Scaffold inside the screen we want to add this navigation bar.

Important note: Unlike Tabs, in navigation bars there are no controllers that connect the view to the widget to be displayed. That's why we have to define our currentPageIndex (outside at class level), update it with the onDestinationSelected property and use it both in the selectedIndex so that it can be painted properly, and use it inside the body so that when we reload the view with setState() it displays the appropriate widget.

Dart code in Flutter to create a Scaffold widget built with a bottomNavigationBar.

With the indicatorColor property we can tell it the colour we want to display when an element is selected.

Finally, we still have to talk about the body. In it we will put the pages we want to display and we must respect the order we have put in the NavigationDestination array.

View/Screen VS Page. Which is which?

This concept is something that I have to explain very often and that is why I dedicate a whole section of this article to it. 

A View or Screen (both meaning the same) is a widget that it contains a Scaffold widget and must be routed in one of the ways we have seen in other posts.

A Page is a widget inside of a View or Screen that by itself it doesn't contain a Scaffold widget and can be loaded by simply changing the widget on view or screen refresh with setState().

Both the View/Screen and the Page are recommended to be wrapped in StatefulWidget or StatelessWidget but as you can imagine, for a View or Screen to be able to load different pages, the view or screen containing the navigation bar must be StatefulWidget in order to be able to reload the view by reacting between the different clicks of the navigation bar.


As you have seen, it is very easy to implement a navigation bar with Material Design 3. It is not necessary to work with routing from the screen as it unnecessarily clutters the screen logic. The reason why I prefer this type of navigation bar to the custom ones, even though some of them are quite popular, is that the Material Design ones are mainly adapted for all types of screens and platforms. Besides, being maintained by Google gives me enough peace of mind to know that they will continue to provide support and updates for what's to come for this technology. 


Post a Comment

© 2020 Mobile Dev Hub