Create A Responsive Sidebar Menu With Angular Material

In this blog, I’m going to walk you through creating a truly responsive sidebar navigation menu in Angular using the Angular Material library. Sidebar navigation menus are the most common layout pattern used by web apps nowadays. But most of the components that we have are not really responsive.

More specifically what I mean by a responsive sidebar is the following.

On the desktop or larger screen sizes, we have enough real estate, so we’d like the sidebar to remain visible at all times, reminding the user of the different sections of the site. On smaller screen sizes, we’d like to hide the sidebar and show it only when the user wants to navigate to another section. Here is the final result of our tutorial showing this behavior.

Pretty clean and understood, right? Let’s get started to see exactly how to do this!

Setting up our project,

Let’s first set up our Angular project by running the following commands on our terminal (with the Angular CLI).

ng new angular-responsive-sidebar
ng add @angular/material

These commands create an Angular app and add the Angular Material components library to it. Let us now import the modules we require in our app.module.ts file.

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { MatToolbarModule } from '@angular/material/toolbar';
import { MatSidenavModule } from '@angular/material/sidenav';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { MatDividerModule } from '@angular/material/divider';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    BrowserAnimationsModule,
    MatToolbarModule,
    MatSidenavModule,
    MatButtonModule,
    MatIconModule,
    MatDividerModule,
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Great, now we can move on to add our component in the template!

Setup our toolbar and sidebar components

Let’s add the material toolbar and the material side navigation bar to our main app.component.html file.

<mat-toolbar> 
   Responsive side bar
</mat-toolbar>

<mat-sidenav-container>
    <mat-sidenav>
    </mat-sidenav>
    <mat-sidenav-content>
        <div class="content mat-elevation-z8">
            Main content here!
        </div>
    </mat-sidenav-content>
</mat-sidenav-container>

As you can see, the material side navigation component has some parts to it. The container is actually called the mat-sidenav-container. This has the mat-sidenav and the mat-sidenav-content sections inside of it.

mat-sidenav is your sidebar menu while mat-sidenav-content is the main content of your app. You could keep any content here, including a router outlet. You’ll most probably be using routes to show different sections of the site here. In our case, I’ve just kept some text to show it’s the main content.

Let’s now see how we added some styles to spice up the layout!

Styling our layout to give an elevated look

Here is how our app.component.scss file looks like for now.

mat-toolbar {
    background: #006880;
    color: white;
}

mat-sidenav {
    margin: 16px;
    width: 250px;
    border-right: none;
    background: #006880;
    color: white;
    border-radius: 10px;
    padding: 16px;
    text-align: center;
}

.content {
    height: calc(100vh - 98px);
    border-radius: 10px;
    margin: 16px;
    margin-left: 32px;

    display: flex;
    justify-content: center;
    align-items: center;

    font-size: 2rem;
    color: lightgray;
}

mat-sidenav-container {
    height: calc(100vh - 65px);
}

What we’ve done here is add some background and foreground colors to set up our design. Then, we’ve added margins for the sections to appear with some spacing between them.

Lastly, we’ve added some tweaks such as a rounded border and some elevation using the mat-elevation-z8 class which comes with the material.

<mat-sidenav class="mat-elevation-z8">
...
</mat-sidenav>

<mat-sidenav-content>
   <div class="content mat-elevation-z8">
       Main content here!
   </div>
</mat-sidenav-content>

Styling our sidebar and adding the menu items

This is strictly not needed for this app, but I wanted to make a more complete example of a sidebar. If you’re more interested in the functionality of the responsive sidebar in Angular, please skip to the next section!

Ok, let’s now add some menu items aka buttons to the sidebar.

<mat-sidenav class="mat-elevation-z8">
        <button mat-button class="menu-button">
            <mat-icon>home</mat-icon>
            <span>Home</span>
        </button>
        <button mat-button class="menu-button">
            <mat-icon>person</mat-icon>
            <span>Profile</span>
        </button>
        <button mat-button class="menu-button">
            <mat-icon>info</mat-icon>
            <span>About</span>
        </button>

        <mat-divider></mat-divider>

        <button mat-button class="menu-button">
            <mat-icon>help</mat-icon>
            <span>Help</span>
        </button>

</mat-sidenav>

This is pretty standard stuff – some material button components with icons related to them. In a real app obviously, you’ll also have routerLink on each of them linking to the different routes of your app. Here is how it looks like (with some styling which I’ll show in a bit).

To make it more real, let’s also add a section at the top of the sidebar with the profile of a user.

<img class="avatar mat-elevation-z8" src="https://media-exp1.licdn.com/dms/image/C5103AQGpGQxef6t_UQ/profile-displayphoto-shrink_200_200/0/1586062520890?e=1637798400&v=beta&t=GeHvic6TgEyFSYx_PDuHmzZKpMdkKz36Vyb3JMQ-gs0" />

   <h4 class="name">Nayan Raval</h4>
   <p class="designation">Web Developer</p>

<mat-divider></mat-divider>

And the styles associated with these elements.

.menu-button {
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: flex-start;
    font-size: 1rem;

    mat-icon {
        margin-right: 8px;
    }
}

.avatar {
    margin-top: 16px;
    width: 100px;
    height: 100px;
    border-radius: 50%;
}

.name {
    margin-top: 8px;
    font-weight: normal;
}

.designation {
    margin-top: 2px;
    font-size: 0.7rem;
    color: lightgrey;
}

mat-divider {
    margin-top: 16px;
    margin-bottom: 16px;
    background-color: rgba(255, 255, 255, 0.5);
}

/* smartphones, Android phones, landscape iPhone */
@media only screen and (max-device-width: 800px) {
    .content{
        margin-left: 16px;
    }
}

For the most part, the styles have the colors and spacing needed for each of the elements. The avatar also has a border-radius to give it the shape of a circle. And that’s pretty much it!

Making the sidebar responsive

To make the sidebar responsive, the material sidenav component provides us with a property called mode. For large screen sizes, we want the mode to be side. This means that the sidenav will always remain visible and our main content displayed with it.

The other mode is over. We’ll need this when we want the sidebar to be hidden normally, but only appear over the content when we want to navigate to some other section.

So all we need is a way to switch between these modes when the screen size changes. Fortunately, we can detect screen size changes with the Angular CDK layout package and its BreakpointObserver service. Let’s see some code!

import { AfterViewInit, Component, ViewChild } from '@angular/core';
import { MatSidenav } from '@angular/material/sidenav';
import { BreakpointObserver } from '@angular/cdk/layout';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent implements AfterViewInit   {
  title = 'angular-responsive-sidebar';
  @ViewChild(MatSidenav)
  sidenav!: MatSidenav;
 
   constructor(private observer: BreakpointObserver) {}
 
   ngAfterViewInit() {
    setTimeout(() => {
      this.observer.observe(['(max-width: 800px)']).subscribe((res) => {
        if (res.matches) {
          this.sidenav.mode = 'over';
          this.sidenav.close();
        } else {
          this.sidenav.mode = 'side';
          this.sidenav.open();
        }
      });
    }, 1);
   }
}

*Note: Remember to keep the subscription in the ngAfterViewInit lifecycle method, so that we’re assured we have the sidenav initialized before calling it!

Adding the sidebar menu toggle button for small screens

But wait, while the sidebar navigation menu hides on smaller screens, we have no way for it to show itself when we need it. We need a menu toggle button to allow the opening and closing of the menu on smaller screens! Let’s add that now.

<mat-toolbar class="mat-elevation-z8">
    <button mat-icon-button *ngIf="sidenav.mode === 'over'" (click)="sidenav.toggle()">
        <mat-icon *ngIf="!sidenav.opened">
            menu
        </mat-icon>
        <mat-icon *ngIf="sidenav.opened">
            close
        </mat-icon>
    </button>
    Responsive side bar
</mat-toolbar>

<mat-sidenav #sidenav="matSidenav" class="mat-elevation-z8">
    ...
</mat-sidenav>

And that’s it! Here’s our finished product again. A clean and understood responsive sidebar in Angular for you.

If we give some thought to it, this can be combined with other components to make them responsive as well with not much effort – providing an intuitive interface to your users whichever platform they use!

This article provides one way of making a responsive sidebar in Angular with material components and the CDK package.

I hope you guys understand how I can do this. Let me know if you face any difficulties.

You can watch my previous blog here.

The complete code for this tutorial can be found at this github repository.

Happy Coding {;} ????

2 Comments

  1. Umang Ramani

    Thank you for providing such useful information. It was quite beneficial to me. I’m constantly looking for high-quality stuff to read, and I finally found it in your post. Continue your good work!

    1
    0
    Reply
    1. Nayan Raval

      Thank you

      0
      0
      Reply

Submit a Comment

Your email address will not be published. Required fields are marked *

Subscribe

Select Categories