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. In this article I’m going to walk you through creating a truly responsive sidebar navigation menu in Angular using the Angular Material library.
More specifically what I mean by a responsive sidebar is the following.
On 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 intuitive, right? Let’s get started to see exactly how to do this!
Video tutorial
Check out the video tutorial below. Or if you’re more of a reader, continue with the text version! 🙂
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.
@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 components in the template!
Adding 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 navigation
</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: #004a9f;
color: white;
}
mat-sidenav {
margin: 16px;
width: 200px;
border-right: none;
background: #002b5c;
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 setup our design. Then, we’ve added margins for the sections to appear with some spacing between them. The fixed heights are there so the sections appear completely on the page (any scrolling will be inside of them).
Lastly, we’ve added some tweaks such as a rounded border and some elevation using the mat-elevation-z8 class which comes with 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>
As a result, we have our basic layout all set up like below.

Great! Let’s add some menu items and styling to our sidebar navigation menu now.
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://source.unsplash.com/c_GmwfHBDzk/200x200" />
<h4 class="name">John Smith</h4>
<p class="designation">Software Engineer</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);
}
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!

Nice. This looks much more authentic and can very well be used in a real app. Now that our sidebar looks good, let’s move on to making it responsive!
Check out my related article on creating a responsive card grid in Angular here.
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!
export class AppComponent {
@ViewChild(MatSidenav)
sidenav!: MatSidenav;
constructor(private observer: BreakpointObserver) {}
ngAfterViewInit() {
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();
}
});
}
}
There are a few things going on here. Let’s go through them one by one.
First, we have a ViewChild decorator at the very top to get the MatSidenav component reference in our code. Then, we include the BreakpointObserver service in our constructor.
We’re using the observe method of the BreakpointObserver which can take in any number of breakpoints. If any of them matches or changes state (i.e. stops matching), all subscriptions to the method are notified.
In our case, we’re using 800px as our breakpoint. This means if it matches, we’ve to switch to the over mode for our sidebar and close it. And vice versa, if it doesn’t match.
Remember to keep the subscription in the ngAfterViewInit lifecycle method, so that we’re assured we have the sidenav initialized before calling it!
Great! Now if you reduce and increase your screen width using Developer tools, you’ll be able to see the sidebar appearing and disappearing as we want 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 allow 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 navigation
</mat-toolbar>
<mat-sidenav #sidenav="matSidenav" class="mat-elevation-z8">
...
</mat-sidenav>
The first thing you need to note is at the very bottom. We’ve added a template variable for the sidenav component using the #sidenav="matSidenav"
syntax. This is basically doing the same thing as we did with the ViewChild decorator before, but this makes the reference available in the template.
For the toggle button, we’re using a material icon button. We’ve added an *ngIf directive to it so that it only shows when the sidenav has the over mode, which will happen on smaller screens. The button’s click event simply calls the toggle function of the sidenav component.
Lastly, we add some additional *ngIf directives to check whether the sidenav is open or not and show a different icon so it’s visually clear to the user.
And that’s it! Here’s our finished product again. A clean and intuitive responsive sidebar in Angular for you 🔥
Conclusion
With the proliferation of tablets and mobiles nowadays, it is a given that your web app needs to be responsive in its layout. This article provides for one way of making a responsive sidebar in Angular with material components and the CDK package.
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!
I hope you’ve found this useful in some way. If so, check out my other related articles below and/or follow me on twitter for updates on future articles!
The complete code for this tutorial can be found at this github repository.
Thanks for reading! Bye 😊
This is the coolest sidenav i have ever seen. Congrats!
The only thing i wonder is how do i close the sidenav on mobile on clicking a button (and not closing on desktop also).
Great stuff!
Thank you!
Hey Marius!
Thanks for the compliment! 🙂
About your question, the sidenav can be closed using the close button or clicking on the content area.
On desktop, the sidenav remains visible always, so I’m not sure what you mean by closing it?
Regards
Where is your working code on github 🙂
Hey Badr!
It’s right there at the end 🙂
Thanks for the tutorial! This was very helpful.
Hello,
Modules imported in app.module.ts are throwing error for me.
BrowserModule,
AppRoutingModule,
BrowserAnimationsModule,
MatToolbarModule,
MatSidenavModule,
MatButtonModule,
MatIconModule,
MatDividerModule,
Here is the error messge: Cannot find name ‘MatToolbarModule’.
Hey Paras!
You need to import the modules from the @angular/material package. For example, for MatToolbarModule use
import { MatToolbarModule } from ‘@angular/material/toolbar’;
Please check the code at the github repository given at the end!
Regards,
Zoaib
cant see the side-nav;
what can it be?
Hey Merav,
Please check the code at the end of the post and compare with that. Something must be missing! If not, create a stackblitz and post here so I can take a look.
Regards,
Zoaib
Hi Zoaib! thanks for the video, is Excellent!!! however, the console gives an error, I have also tried it from your repository.
The error is as follows:
Error: NG0100: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: ‘true’. Current value: ‘false’.
The error disappears if I load the app from the mobile view, but not from the desktop view.
Do you know how it can be solved?
thanks very much!!!!
Hey Ida,
The Expression Changed Error is basically just a development time error, to highlight issues when values are changed during a change detection cycle. In this case, when the app first loads, the responsive handler fires immediately causing the sidebar to open up – this causes a change in the sidebar state after the change detection cycle has run – hence the error.
The quickest way to resolve this is to introduce a slight delay which schedules the event handler to the next change detection cycle. I’ve made that and updated the demo app as well.
There are several other ways it can be handled as well though, but I didn’t see worth going through them when the app is pretty much functional.
Regards,
Zoaib
Hi !! Thank you very much for answering…
now if it works perfectly.
I’ve implemented this and it works great! In order to get the main content window to align to the top (rather than center), I had to change `.content` to have `align-items: flex-start;`. Is it possible to add another rule to the content class that makes its contents their width to fit? I’ve found I have to add `min-width: 600px` to forms and tables to get them to look good.
Steps to reproduce:
git clone https://github.com/manfredsteyer/angular-crud.git
cd angular-crud/demo-material
npm i
npm start
Click on flights. If you look at flight-edit.component.ts or flight-list.component.ts, you’ll see they both have style rules to stretch things out.
amazing video.
I am learning angular and video like this will help me learn concepts in detail.
Thanks Siddharth! Glad you found it useful 🙂
Hello, Thanks for the tutorial!
But I need your guidance on what changes I need to make if I want to put side bar menu on the right
Hey Hoda!
Thanks for the comment. For putting the sidebar menu on the right, there is a property of the sidenav you can set called “position”. Set it to “end” in the template file and the menu should shift to the right. Then, you’ll have to adjust some margins in the styles so that everything appears ok.
Hope this helps!
Thank you very much for your reply…
I can’t see the the sidebar. I want this sidebar after on my login page. Thanks for this tutorial! More angular tutorial
hii,
I tried this, its working. I gave router links to that home ,profile components.After clicking that components,the content is displaying in the next page below the sidenavbar ,rather than displaying in the middile of the same page with sidenavbar.could uu hellp me in this.
Hey Geetha,
Thanks for the comment. Could you please provide a stackblitz with your code or show some of your code so I can take a look?
Regards,
Zoaib
Hi, Thanks for a simple coding but it would be much better if you provide a nested menu / sub menu in sidebar.
You’re welcome!
I’m working on improving this further, so hopefully soon 🙂
Thank you very much Zoaib for this great article. You just unlocked my project in so many ways.
You’re welcome Nicholas! Glad it was some help 🙂
I really liked the guide, but I would like to know how to load content in content when clicking on a button.
I’ll be creating a post/video esp for this in the near future hopefully 🙂
[…] followed this guide to create a responsive sidebar menu with Angular Material. Now I’m trying to make the content […]
i want dropdown menu and submenu in sidenav menu
Hello Zohaib,
Thank you so much for such a nice tutorial. I have implemented it and it is great. I just have a question it would be great if you please answer it. In my implementation, I am rendering some components based on routing like that
the routing and everything working fine but I have two scrollbars one of the browsers and one of the mat-sidenav-content. if I remove that router outlet then the sidenav scrollbar removed but I can not render different components inside the content. I want to only keep the browser scrollbar. Can you please help me?
Hi Zoaib,
first of all thank you for the tutorial.
I also got the error, some had – my sidebar was not showing (the toolbar was showing fine). I downloaded your code and it works of course. I made 1 on 1 compassions, but couldn’t really find why the sidebar is not showing.
Then I found out, that the ngAfterViewInit() / observer code in app.component was needed to have the sidebar shown. You should be able to reproduce the “error”, by creating a fresh project and working though the project until “Styling our sidebar and adding the menu items”.
I still would be interested to understand this issue. So if you have an idea let me know.
Thank you,
Daniel
working fine, not break the app but through the following error in console:
“ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: ‘true’. Current value: ‘false’.”
Thank you & great article! A few additions I’d like to suggest which I found when using bits from this tutorial.
Firstly: Angular 8 introduced the static parameter for ViewChild, which basically specifies whether the ViewChild element is dynamically injected or not. In most cases it is so the default is false, however for this SideNav; as it’s a static element this can be set to true which initialises the element OnInit.
@ViewChild(MatSidenav, { static: true}) sidenav!: MatSidenav;
Doing this initialises the element on component init, meaning we can rid of the AfterViewInit lifecycle as it will be available on component instatiation.
ngOnInit(): void {
this.observer.observe([‘(max-width: 800px)’]).subscribe((res) => {
…
}
Doing this and placing the above observer inside the onInit() lifecycle fixes the:
“ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: ‘true’. Current value: ‘false’.” error and means you can remove the rxjs delay workaround.
@Mehran @Daniel
Oh nice! Didn’t realize the static parameter could resolve this issue. That ExpressionChangedAfterItHasBeenCheckedError has always been a confusing error for me personally.
Thanks!