Adding Expandable Side Bar using NavigationRail in Flutter.
Tags: flutter, tutorial, flutterweb
Published: 2022-07-23 17:58:00

If this is what you want to achieve, then this post is for you.

![Flutter Web With Expandable Sidebar](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mppqtwgekgdsu1ofkpyo.gif)
 


Normally, for the mobile app, using the **BottomNavigationBar** would be fine. However, BottomNavigationBar for a desktop website? No one do that! 

So here is the alternative. 
Introducing **NavigationRail**, this is an ideal widget for implementing sidebar on the web/desktop application.


### 1. Where to Put? 

Well, since it's a sidebar, therefore this widget will be insert in the either left or right side of your page, and in order to do that, we will use **Row** widget.



```dart
class PageWithSideBar extends StatefulWidget {
  const PageWithSideBar({Key? key}) : super(key: key);

  @override
  State<PageWithSideBar> createState() => _PageWithSideBarState();
}

class _PageWithSideBarState extends State<PageWithSideBar> {
  int _selectedIndex = 0;
  final List<String> _destinations = ['Home', 'Calendar', 'Email'];
  
  Widget _buildNavigationRail() {
    return Container() //TODO: We are going to implement here
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Row(
        children: <Widget>[
          _buildNavigationRail(), // HERE: This is our SideBar
          Expanded(
            child: Center(
              child: Text('This is ${_destinations[_selectedIndex]} Page'),
            ),
          )
        ],
      ),
    );
  }
}


```
Notice that we use **Expanded** widget in our main content so it will take all the space as much as possible.

### 2. Now let's implement **NavigationRail**.


```dart
Widget _buildNavigationRail() {
    return NavigationRail(
      labelType: NavigationRailLabelType.selected,
      selectedIndex: _selectedIndex,
      onDestinationSelected: (int index) {
        setState(() {
          _selectedIndex = index;
        });
      },
      destinations: const <NavigationRailDestination>[
        NavigationRailDestination(
          icon: Icon(Icons.home_outlined),
          selectedIcon: Icon(Icons.home),
          label: Text('Home'),
        ),
        NavigationRailDestination(
          icon: Icon(Icons.calendar_month_outlined),
          selectedIcon: Icon(Icons.calendar_month),
          label: Text('Calendar'),
        ),
        NavigationRailDestination(
          icon: Icon(Icons.email_outlined),
          selectedIcon: Icon(Icons.email),
          label: Text('Email'),
        ),
      ],
    );
  }

```

Let's see how it turned out

![Flutter Web With Sidebar](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7g5hst6oji1yvcnnt5re.gif)
 

In my opinion, this sidebar still look like an mobile one, so what about make it feel more like a website's sidebar?

We are going to do that by make it become **Expandable** side bar. Good news is that the Flutter Dev know exactly what we want, as there is an property call **extended**, so why don't we set its value to "true"?

``` dart
NavigationRail(
extended: true, 
labelType: NavigationRailLabelType.selected, ...)

```

![Flutter Sidebar Error](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ct46yeh5u0xhupmcuvox.png)
 
Whoa, There is error here. It's mention that if we set the "extended" to true, then we have to set the labelType to "none"
Okay understandable, since having both label at the bottom of the icon and next to the icon would be really weird.

``` dart
NavigationRail(
extended: true,   
labelType: NavigationRailLabelType.none, ...)
```
Now the error is gone

![Flutter Web With Expandable Sidebar](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q4f4ey1wlrm4w2c7j8zp.png)

But hey, seems like something is missing here... It should be togglable, so we should have something like menu icon.

Okay, here is my solution, 
1. Declare new boolean variable call _isExtended as a property of NavigationRail
2. Add AppBar with the IconButton to toggle the state of _isExtended


Here is the code
``` dart
class PageWithSideBar extends StatefulWidget {
  const PageWithSideBar({Key? key}) : super(key: key);

  @override
  State<PageWithSideBar> createState() => _PageWithSideBarState();
}

class _PageWithSideBarState extends State<PageWithSideBar> {
  int _selectedIndex = 0;
  final List<String> _destinations = ['Home', 'Calendar', 'Email'];
  bool _isExpanded = false; //NEW VARIABLE
  Widget _buildNavigationRail() {
    return NavigationRail(
      extended: _isExpanded, //NEW VARIABLE
      labelType: NavigationRailLabelType.none,
      selectedIndex: _selectedIndex,
      onDestinationSelected: (int index) {
        setState(() {
          _selectedIndex = index;
        });
      },
      destinations: const <NavigationRailDestination>[
        NavigationRailDestination(
          icon: Icon(Icons.home_outlined),
          selectedIcon: Icon(Icons.home),
          label: Text('Home'),
        ),
        NavigationRailDestination(
          icon: Icon(Icons.calendar_month_outlined),
          selectedIcon: Icon(Icons.calendar_month),
          label: Text('Calendar'),
        ),
        NavigationRailDestination(
          icon: Icon(Icons.email_outlined),
          selectedIcon: Icon(Icons.email),
          label: Text('Email'),
        ),
      ],
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar( //ADDED APP BAR
        title: const Text('Navigation Rails Example'),
        leading: IconButton( 
          icon: const Icon(Icons.menu),
          onPressed: () {
            setState(() {
              _isExpanded = !_isExpanded;
            });
          },
        ),
      ),
      body: Row(
        children: <Widget>[
          _buildNavigationRail(),
          Expanded(
            child: Center(
              child: Text('This is ${_destinations[_selectedIndex]} Page'),
            ),
          )
        ],
      ),
    );
  }
}
```
Here is the results 
![Flutter Web With Expandable Sidebar](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4ktvgqe32l9gjhzvdugj.gif)
 
Here is the full code

``` dart
import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  static const String _title = 'Navigation Rails Example';

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      title: _title,
      home: PageWithSideBar(),
    );
  }
}

class PageWithSideBar extends StatefulWidget {
  const PageWithSideBar({Key? key}) : super(key: key);

  @override
  State<PageWithSideBar> createState() => _PageWithSideBarState();
}

class _PageWithSideBarState extends State<PageWithSideBar> {
  int _selectedIndex = 0;
  final List<String> _destinations = ['Home', 'Calendar', 'Email'];
  bool _isExpanded = false; 
  Widget _buildNavigationRail() {
    return NavigationRail(
      extended: _isExpanded, 
      labelType: NavigationRailLabelType.none,
      selectedIndex: _selectedIndex,
      onDestinationSelected: (int index) {
        setState(() {
          _selectedIndex = index;
        });
      },
      destinations: const <NavigationRailDestination>[
        NavigationRailDestination(
          icon: Icon(Icons.home_outlined),
          selectedIcon: Icon(Icons.home),
          label: Text('Home'),
        ),
        NavigationRailDestination(
          icon: Icon(Icons.calendar_month_outlined),
          selectedIcon: Icon(Icons.calendar_month),
          label: Text('Calendar'),
        ),
        NavigationRailDestination(
          icon: Icon(Icons.email_outlined),
          selectedIcon: Icon(Icons.email),
          label: Text('Email'),
        ),
      ],
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar( //ADDED APP BAR
        title: const Text('Navigation Rails Example'),
        leading: IconButton( 
          icon: const Icon(Icons.menu),
          onPressed: () {
            setState(() {
              _isExpanded = !_isExpanded;
            });
          },
        ),
      ),
      body: Row(
        children: <Widget>[
          _buildNavigationRail(),
          Expanded(
            child: Center(
              child: Text('This is ${_destinations[_selectedIndex]} Page'),
            ),
          )
        ],
      ),
    );
  }
}

```
Ok we are good to go now. 

_Thank you for reading._