shou2017.com
JP

Creating a Navigation Drawer with Angular Material

Sat Aug 10, 2019
Sat Aug 10, 2024

Environment

  • macOS Mojave 10.14.4
  • Angular CLI: 8.2.0
  • Node: 10.16.0
  • OS: darwin x64
  • Angular: 8.2.0
  • @angular/material 8.1.2
  • rxjs 6.4.0
  • typescript 3.5.3

Before implementing the navigation drawer from Angular Material, we’ll apply flex layout. Since it’s frequently used when adopting material design, I’m making a note of it.

So, let’s start by installing flex-layout. We can install it using Angular CLI.

Using Angular CLI

$ npm install @angular/flex-layout @angular/cdk --save

After installation, add it to app.module.ts.

<!--  src/app/app.module.ts -->

import {NgModule} from '@angular/core';
import {FlexLayoutModule} from '@angular/flex-layout;
// other imports 
@NgModule({
  imports: [FlexLayoutModule],
  ...
})
export class AppModule {}

Angular Sidenav

Import MatSidenavModule. Since the side navigation will be common across all pages, we’ll structure app.component.html like this:

<!-- app.component.html -->
<mat-sidenav-container>
  <mat-sidenav #sidenav role="navigation">
    <p>This is the side navigation</p>
  </mat-sidenav>
  <mat-sidenav-content>
    <button (click)="sidenav.toggle()">show</button>
    <router-outlet></router-outlet>
  </mat-sidenav-content>
</mat-sidenav-container>

When you press the show button, the navigation content should appear.

This is the basic structure. Now we’ll refine it to make it look nicer.

Final Version

<!-- app.component.html -->

<mat-sidenav-container>
  <mat-sidenav #sidenav role="navigation">
    <mat-nav-list>
      <a mat-list-item href="#" (click)="sidenav.close()">
        <mat-icon>face</mat-icon>
        <span class="nav-caption">Create New</span>
      </a>
      <a mat-list-item href="#" (click)="sidenav.close()">
        <mat-icon>input</mat-icon>
        <span class="nav-caption">Login</span>
      </a>
      <mat-list-item>
        <button mat-icon-button (click)="sidenav.close()">
          <mat-icon>eject</mat-icon>
          <span class="nav-caption">Logout</span>
        </button>
      </mat-list-item>
    </mat-nav-list>
  </mat-sidenav>
  <mat-sidenav-content>
    <mat-toolbar color="primary">
      <div fxHide.gt-xs>
        <button mat-icon-button (click)="sidenav.toggle()">
          <mat-icon>menu</mat-icon>
        </button></div>
      <div><a routerLink="/">LOGO</a></div>
      <div fxFlex fxLayout fxLayoutAlign="flex-end" fxHide.xs>
        <ul fxLayout fxLayoutGap="10px" class="navigation-items" >
          <li><a href="#">Create New</a></li>
          <li><a href="#">Login</a></li>
        </ul>
      </div>
    </mat-toolbar>
    <main>
      <router-outlet></router-outlet>
    </main>
  </mat-sidenav-content>
</mat-sidenav-container>

We set the reference variable #sidenav on mat-sidenav to enable access to sidenav.close from mat-list-item. This makes the side navigation close when a list item is clicked.

We use fxHide from flex-layout to hide elements when the screen gets smaller.

Styling and Refinement

Let’s create a design that makes the navigation drawer fill the screen. Here’s the complete styling:

/* app.component.scss */

mat-sidenav-container, mat-sidenav-content mat-sidenav {
  height: 100%;
}

mat-sidenav {
  width: 250px;
}

a {
  text-decoration: none;
  color: white;
}

a:hover,
a:active {
  color: lightgray;
}

.navigation-items {
  list-style: none;
  padding: 0;
  margin: 0;
}

.nav-caption {
  display: inline-block;
  padding-left: 6px;
}

We also need to set the height in styles.scss for the overall layout:

/* styles.scss */

/* You can add global styles to this file, and also import other style files */
@import "~@angular/material/prebuilt-themes/indigo-pink.css";

html, body {
  height: 100%;
}

body {
  margin: 0;
}

References

Angular Flex-Layout

Angular Sidenav

See Also