Sidenav

Overview for sidenav

Angular Material provides two sets of components designed to add collapsible side content (often navigation, though it can be any content) alongside some primary content. These are the sidenav and drawer components.

The sidenav components are designed to add side content to a fullscreen app. To set up a sidenav we use three components: <mat-sidenav-container> which acts as a structural container for our content and sidenav, <mat-sidenav-content> which represents the main content, and <mat-sidenav> which represents the added side content.

Basic sidenav
Please open on Stackblitz to see result

The drawer component is designed to add side content to a small section of your app. This is accomplished using the <mat-drawer-container>, <mat-drawer-content>, and <mat-drawer> components, which are analogous to their sidenav equivalents. Rather than adding side content to the app as a whole, these are designed to add side content to a small section of your app. They support almost all of the same features, but do not support fixed positioning.

Basic drawer
Drawer content
Main content

Both the main and side content should be placed inside of the <mat-sidenav-container>, content that you don't want to be affected by the sidenav, such as a header or footer, can be placed outside of the container.

The side content should be wrapped in a <mat-sidenav> element. The position property can be used to specify which end of the main content to place the side content on. position can be either start or end which places the side content on the left or right respectively in left-to-right languages. If the position is not set, the default value of start will be assumed. A <mat-sidenav-container> can have up to two <mat-sidenav> elements total, but only one for any given side. The <mat-sidenav> must be placed as an immediate child of the <mat-sidenav-container>.

The main content should be wrapped in a <mat-sidenav-content>. If no <mat-sidenav-content> is specified for a <mat-sidenav-container>, one will be created implicitly and all of the content inside the <mat-sidenav-container> other than the <mat-sidenav> elements will be placed inside of it.

Implicit main content with two sidenavs
Please open on Stackblitz to see result

The following are examples of valid sidenav layouts:

<!-- Creates a layout with a left-positioned sidenav and explicit content. -->
<mat-sidenav-container>
  <mat-sidenav>Start</mat-sidenav>
  <mat-sidenav-content>Main</mat-sidenav-content>
</mat-sidenav-container>
<!-- Creates a layout with a left and right sidenav and implicit content. -->
<mat-sidenav-container>
  <mat-sidenav>Start</mat-sidenav>
  <mat-sidenav position="end">End</mat-sidenav>
  <section>Main</section>
</mat-sidenav-container>
<!-- Creates an empty sidenav container with no sidenavs and implicit empty content. -->
<mat-sidenav-container></mat-sidenav-container>

And these are examples of invalid sidenav layouts:

<!-- Invalid because there are two `start` position sidenavs. -->
<mat-sidenav-container>
  <mat-sidenav>Start</mat-sidenav>
  <mat-sidenav position="start">Start 2</mat-sidenav>
</mat-sidenav-container>
<!-- Invalid because there are multiple `<mat-sidenav-content>` elements. -->
<mat-sidenav-container>
  <mat-sidenav-content>Main</mat-sidenav-content>
  <mat-sidenav-content>Main 2</mat-sidenav-content>
</mat-sidenav-container>
<!-- Invalid because the `<mat-sidenav>` is outside of the `<mat-sidenav-container>`. -->
<mat-sidenav-container></mat-sidenav-container>
<mat-sidenav></mat-sidenav>

These same rules all apply to the drawer components as well.

A <mat-sidenav> can be opened or closed using the open(), close() and toggle() methods. Each of these methods returns a Promise<boolean> that will be resolved with true when the sidenav finishes opening or false when it finishes closing.

The opened state can also be set via a property binding in the template using the opened property. The property supports 2-way binding.

<mat-sidenav> also supports output properties for just open and just close events, The (opened) and (closed) properties respectively.

Sidenav open & close behavior
Please open on Stackblitz to see result

All of these properties and methods work on <mat-drawer> as well.

The <mat-sidenav> can render in one of three different ways based on the mode property.

Mode Description
over Sidenav floats over the primary content, which is covered by a backdrop
push Sidenav pushes the primary content out of its way, also covering it with a backdrop
side Sidenav appears side-by-side with the main content, shrinking the main content's width to make space for the sidenav.

If no mode is specified, over is used by default.

Sidenav with configurable mode
Please open on Stackblitz to see result

The over and push sidenav modes show a backdrop by default, while the side mode does not. This can be customized by setting the hasBackdrop property on mat-sidenav-container. Explicitly setting hasBackdrop to true or false will override the default backdrop visibility setting for all sidenavs regadless of mode. Leaving the property unset or setting it to null will use the default backdrop visibility for each mode.

Drawer with explicit backdrop setting

<mat-drawer> also supports all of these same modes and options.

Clicking on the backdrop or pressing the Esc key will normally close an open sidenav. However, this automatic closing behavior can be disabled by setting the disableClose property on the <mat-sidenav> or <mat-drawer> that you want to disable the behavior for.

Custom handling for Esc can be done by adding a keydown listener to the <mat-sidenav>. Custom handling for backdrop clicks can be done via the (backdropClick) output property on <mat-sidenav-container>.

Sidenav with custom escape and backdrop click behavior
Please open on Stackblitz to see result

By default, Material will only measure and resize the drawer container in a few key moments (on open, on window resize, on mode change) in order to avoid layout thrashing, however there are cases where this can be problematic. If your app requires for a drawer to change its width while it is open, you can use the autosize option to tell Material to continue measuring it. Note that you should use this option at your own risk, because it could cause performance issues.

Autosize sidenav

The <mat-sidenav> and <mat-drawer> will, by default, fit the size of its content. The width can be explicitly set via CSS:

mat-sidenav {
  width: 200px;
}

Try to avoid percent based width as resize events are not (yet) supported.

For <mat-sidenav> only (not <mat-drawer>) fixed positioning is supported. It can be enabled by setting the fixedInViewport property. Additionally, top and bottom space can be set via the fixedTopGap and fixedBottomGap. These properties accept a pixel value amount of space to add at the top or bottom.

Fixed sidenav
Please open on Stackblitz to see result

A sidenav often needs to behave differently on a mobile vs a desktop display. On a desktop, it may make sense to have just the content section scroll. However, on mobile you often want the body to be the element that scrolls; this allows the address bar to auto-hide. The sidenav can be styled with CSS to adjust to either type of device.

Responsive sidenav
Please open on Stackblitz to see result

To react to scrolling inside the <mat-sidenav-container>, you can get a hold of the underlying CdkScrollable instance through the MatSidenavContainer.

class YourComponent implements AfterViewInit {
  @ViewChild(MatSidenavContainer) sidenavContainer: MatSidenavContainer;

  ngAfterViewInit() {
    this.sidenavContainer.scrollable.elementScrolled().subscribe(() => /* react to scrolling */);
  }
}

The <mat-sidenav> an <mat-sidenav-content> should each be given an appropriate role attribute depending on the context in which they are used.

For example, a <mat-sidenav> that contains links to other pages might be marked role="navigation", whereas one that contains a table of contents about might be marked as role="directory". If there is no more specific role that describes your sidenav, role="region" is recommended.

Similarly, the <mat-sidenav-content> should be given a role based on what it contains. If it represents the primary content of the page, it may make sense to mark it role="main". If no more specific role makes sense, role="region" is again a good fallback.

This error is thrown if you have more than one sidenav or drawer in a given container with the same position. The position property defaults to start, so the issue may just be that you forgot to mark the end sidenav with position="end".