
Security News
The Changelog Podcast: Practical Steps to Stay Safe on npm
Learn the essential steps every developer should take to stay secure on npm and reduce exposure to supply chain attacks.
@material/drawer
Advanced tools
The MDC Drawer component is a spec-aligned drawer component adhering to the Material Design navigation drawer pattern. It implements permanent, persistent, and temporary drawers. Permanent drawers are CSS-only and require no JavaScript, whereas persistent and temporary drawers require JavaScript to function, in order to respond to user interaction.
npm install --save @material/drawer
A permanent drawer is always open, sitting to the side of the content. It is appropriate for any display size larger than mobile.
TODO(sgomes): Give advice on how to hide permanent drawer in mobile.
<nav class="mdc-permanent-drawer mdc-typography">
<div class="mdc-permanent-drawer__toolbar-spacer"></div>
<div class="mdc-permanent-drawer__content">
<nav id="icon-with-text-demo" class="mdc-list">
<a class="mdc-list-item mdc-permanent-drawer--selected" href="#">
<i class="material-icons mdc-list-item__start-detail" aria-hidden="true">inbox</i>Inbox
</a>
<a class="mdc-list-item" href="#">
<i class="material-icons mdc-list-item__start-detail" aria-hidden="true">star</i>Star
</a>
</nav>
</div>
</nav>
<div>
Toolbar and page content go inside here.
</div>
In the example above, we've set the drawer above the toolbar, and are using a toolbar spacer to ensure that it is presented correctly, with the correct amount of space to match the toolbar height. Note that you can place content inside the toolbar spacer.
Permanent drawers can also be set below the toolbar:
<div>Toolbar goes here</div>
<div class="content">
<nav class="mdc-permanent-drawer mdc-typography">
<nav id="icon-with-text-demo" class="mdc-list">
<a class="mdc-list-item mdc-permanent-drawer--selected" href="#">
<i class="material-icons mdc-list-item__start-detail" aria-hidden="true">inbox</i>Inbox
</a>
<a class="mdc-list-item" href="#">
<i class="material-icons mdc-list-item__start-detail" aria-hidden="true">star</i>Star
</a>
</nav>
</nav>
<main>
Page content goes here.
</main>
</div>
CSS classes:
| Class | Description |
|---|---|
mdc-permanent-drawer | Mandatory. Needs to be set on the root element of the component. |
mdc-permanent-drawer__content | Mandatory. Needs to be set on the container node for the drawer content. |
mdc-permanent-drawer__toolbar-spacer | Optional. Add to node to provide the matching amount of space for toolbar. |
Persistent drawers can be toggled open or closed. The drawer sits on the same surface elevation as the content. It is closed by default. When the drawer is outside of the page grid and opens, the drawer forces other content to change size and adapt to the smaller viewport. Persistent drawers stay open until closed by the user.
Persistent drawers are acceptable for all sizes larger than mobile.
<aside class="mdc-persistent-drawer mdc-typography">
<nav class="mdc-persistent-drawer__drawer">
<header class="mdc-persistent-drawer__header">
<div class="mdc-persistent-drawer__header-content">
Header here
</div>
</header>
<nav id="icon-with-text-demo" class="mdc-persistent-drawer__content mdc-list">
<a class="mdc-list-item mdc-persistent-drawer--selected" href="#">
<i class="material-icons mdc-list-item__start-detail" aria-hidden="true">inbox</i>Inbox
</a>
<a class="mdc-list-item" href="#">
<i class="material-icons mdc-list-item__start-detail" aria-hidden="true">star</i>Star
</a>
</nav>
</nav>
</aside>
let drawer = new mdc.drawer.MDCPersistentDrawer(document.querySelector('.mdc-persistent-drawer'));
document.querySelector('.menu').addEventListener('click', () => drawer.open = true);
CSS classes:
| Class | Description |
|---|---|
mdc-persistent-drawer | Mandatory. Needs to be set on the root element of the component. |
mdc-persistent-drawer__drawer | Mandatory. Needs to be set on the container node for the drawer content. |
MDC Persistent Drawer ships with a Component / Foundation combo which allows for frameworks to richly integrate the correct drawer behaviors into idiomatic components.
import {MDCPersistentDrawer, MDCPersistentDrawerFoundation, util} from 'mdc-drawer';
const mdcDrawer = require('mdc-drawer');
const MDCPersistentDrawer = mdcDrawer.MDCPersistentDrawer;
const MDCPersistentDrawerFoundation = mdcDrawer.MDCPersistentDrawerFoundation;
const util = mdcDrawer.util;
require(['path/to/mdc-drawer'], mdcDrawer => {
const MDCPersistentDrawer = mdcDrawer.MDCPersistentDrawer;
const MDCPersistentDrawerFoundation = mdcDrawer.MDCPersistentDrawerFoundation;
const util = mdcDrawer.util;
});
const MDCPersistentDrawer = mdc.drawer.MDCPersistentDrawer;
const MDCPersistentDrawerFoundation = mdc.drawer.MDCPersistentDrawerFoundation;
const util = mdc.drawer.util;
If you do not care about retaining the component instance for the persistent drawer, simply call attachTo()
and pass it a DOM element.
mdc.drawer.MDCPersistentDrawer.attachTo(document.querySelector('.mdc-persistent-drawer'));
Persistent drawers can easily be initialized using their default constructors as well, similar to attachTo.
import {MDCPersistentDrawer} from 'mdc-drawer';
const drawer = new MDCPersistentDrawer(document.querySelector('.mdc-persistent-drawer'));
When the drawer is opened or closed, the component will emit a
MDCPersistentDrawer:open or MDCPersistentDrawer:close custom event with no data attached.
Events get emitted only when the drawer toggles its opened state, i.e. multiple consecutive
drawer.open = true calls will result in only one MDCPersistentDrawer:open.
MDC Persistent Drawer ships with an MDCPersistentDrawerFoundation class that external frameworks and libraries can
use to integrate the component. As with all foundation classes, an adapter object must be provided.
The adapter for persistent drawers must provide the following functions, with correct signatures:
| Method Signature | Description |
|---|---|
addClass(className: string) => void | Adds a class to the root element. |
removeClass(className: string) => void | Removes a class from the root element. |
hasClass(className: string) => boolean | Returns boolean indicating whether element has a given class. |
hasNecessaryDom() => boolean | Returns boolean indicating whether the necessary DOM is present (namely, the mdc-persistent-drawer__drawer drawer container). |
registerInteractionHandler(evt: string, handler: EventListener) => void | Adds an event listener to the root element, for the specified event name. |
deregisterInteractionHandler(evt: string, handler: EventListener) => void | Removes an event listener from the root element, for the specified event name. |
registerDrawerInteractionHandler(evt: string, handler: EventListener) => void | Adds an event listener to the drawer container sub-element, for the specified event name. |
deregisterDrawerInteractionHandler(evt: string, handler: EventListener) => void | Removes an event listener from drawer container sub-element, for the specified event name. |
registerTransitionEndHandler(handler: EventListener) => void | Registers an event handler to be called when a transitionend event is triggered on the drawer container sub-element element. |
deregisterTransitionEndHandler(handler: EventListener) => void | Deregisters an event handler from a transitionend event listener. This will only be called with handlers that have previously been passed to registerTransitionEndHandler calls. |
registerDocumentKeydownHandler(handler: EventListener) => void | Registers an event handler on the document object for a keydown event. |
deregisterDocumentKeydownHandler(handler: EventListener) => void | Deregisters an event handler on the document object for a keydown event. |
getDrawerWidth() => number | Returns the current drawer width, in pixels. |
setTranslateX(value: number) => void | Sets the current position for the drawer, in pixels from the border. |
getFocusableElements() => NodeList | Returns the node list of focusable elements inside the drawer. |
saveElementTabState(el: Element) => void | Saves the current tab index for the element in a data property. |
restoreElementTabState(el: Element) => void | Restores the saved tab index (if any) for an element. |
makeElementUntabbable(el: Element) => void | Makes an element untabbable. |
notifyOpen() => void | Dispatches an event notifying listeners that the drawer has been opened. |
notifyClose() => void | Dispatches an event notifying listeners that the drawer has been closed. |
isRtl() => boolean | Returns boolean indicating whether the current environment is RTL. |
isDrawer(el: Element) => boolean | Returns boolean indicating whether the provided element is the drawer container sub-element. |
A temporary drawer is usually closed, sliding out at a higher elevation than the content when opened. It is appropriate for any display size.
<aside class="mdc-temporary-drawer mdc-typography">
<nav class="mdc-temporary-drawer__drawer">
<header class="mdc-temporary-drawer__header">
<div class="mdc-temporary-drawer__header-content">
Header here
</div>
</header>
<nav id="icon-with-text-demo" class="mdc-temporary-drawer__content mdc-list">
<a class="mdc-list-item mdc-temporary-drawer--selected" href="#">
<i class="material-icons mdc-list-item__start-detail" aria-hidden="true">inbox</i>Inbox
</a>
<a class="mdc-list-item" href="#">
<i class="material-icons mdc-list-item__start-detail" aria-hidden="true">star</i>Star
</a>
</nav>
</nav>
</aside>
let drawer = new mdc.drawer.MDCTemporaryDrawer(document.querySelector('.mdc-temporary-drawer'));
document.querySelector('.menu').addEventListener('click', () => drawer.open = true);
Temporary drawers can use toolbar spacers, headers, or neither.
A toolbar spacer adds to the drawer the same amount of space that the toolbar takes up in your application. This is very useful for visual alignment and consistency. Note that you can place content inside the toolbar spacer.
<aside class="mdc-temporary-drawer mdc-typography">
<nav class="mdc-temporary-drawer__drawer">
<div class="mdc-temporary-drawer__toolbar-spacer"></div>
<nav id="icon-with-text-demo" class="mdc-temporary-drawer__content mdc-list">
<a class="mdc-list-item mdc-temporary-drawer--selected" href="#">
<i class="material-icons mdc-list-item__start-detail" aria-hidden="true">inbox</i>Inbox
</a>
<a class="mdc-list-item" href="#">
<i class="material-icons mdc-list-item__start-detail" aria-hidden="true">star</i>Star
</a>
</nav>
</nav>
</aside>
A header, on the other hand, is a large rectangular area that maintains a 16:9 ratio. It's often used for user account
selection.
It uses an outer mdc-temporary-drawer__header for positioning, with an inner mdc-temporary-drawer__header-content
for placing the actual content, which will be bottom-aligned.
<aside class="mdc-temporary-drawer mdc-typography">
<nav class="mdc-temporary-drawer__drawer">
<header class="mdc-temporary-drawer__header">
<div class="mdc-temporary-drawer__header-content">
Header content goes here
</div>
</header>
<nav id="icon-with-text-demo" class="mdc-temporary-drawer__content mdc-list">
<a class="mdc-list-item mdc-temporary-drawer--selected" href="#">
<i class="material-icons mdc-list-item__start-detail" aria-hidden="true">inbox</i>Inbox
</a>
<a class="mdc-list-item" href="#">
<i class="material-icons mdc-list-item__start-detail" aria-hidden="true">star</i>Star
</a>
</nav>
</nav>
</aside>
CSS classes:
| Class | Description |
|---|---|
mdc-temporary-drawer | Mandatory. Needs to be set on the root element of the component. |
mdc-temporary-drawer__drawer | Mandatory. Needs to be set on the container node for the drawer content. |
mdc-temporary-drawer__content | Optional. Should be set on the list of items inside the drawer. |
mdc-temporary-drawer__toolbar-spacer | Optional. Add to node to provide the matching amount of space for toolbar. |
mdc-temporary-drawer__header | Optional. Add to container node to create a 16:9 drawer header. |
mdc-temporary-drawer__header-content | Optional. Add to content node inside mdc-temporary-drawer__header. |
MDC Temporary Drawer ships with a Component / Foundation combo which allows for frameworks to richly integrate the correct drawer behaviors into idiomatic components.
import {MDCTemporaryDrawer, MDCTemporaryDrawerFoundation, util} from 'mdc-drawer';
const mdcDrawer = require('mdc-drawer');
const MDCTemporaryDrawer = mdcDrawer.MDCTemporaryDrawer;
const MDCTemporaryDrawerFoundation = mdcDrawer.MDCTemporaryDrawerFoundation;
const util = mdcDrawer.util;
require(['path/to/mdc-drawer'], mdcDrawer => {
const MDCTemporaryDrawer = mdcDrawer.MDCTemporaryDrawer;
const MDCTemporaryDrawerFoundation = mdcDrawer.MDCTemporaryDrawerFoundation;
const util = mdcDrawer.util;
});
const MDCTemporaryDrawer = mdc.drawer.MDCTemporaryDrawer;
const MDCTemporaryDrawerFoundation = mdc.drawer.MDCTemporaryDrawerFoundation;
const util = mdc.drawer.util;
If you do not care about retaining the component instance for the temporary drawer, simply call attachTo()
and pass it a DOM element.
mdc.drawer.MDCTemporaryDrawer.attachTo(document.querySelector('.mdc-temporary-drawer'));
Temporary drawers can easily be initialized using their default constructors as well, similar to attachTo.
import {MDCTemporaryDrawer} from 'mdc-drawer';
const drawer = new MDCTemporaryDrawer(document.querySelector('.mdc-temporary-drawer'));
When the drawer is opened or closed, the component will emit a
MDCTemporaryDrawer:open or MDCTemporaryDrawer:close custom event with no data attached.
Events get emitted only when the drawer toggles its opened state, i.e. multiple consecutive
drawer.open = true calls will result in only one MDCTemporaryDrawer:open.
MDC Temporary Drawer ships with an MDCTemporaryDrawerFoundation class that external frameworks and libraries can
use to integrate the component. As with all foundation classes, an adapter object must be provided.
The adapter for temporary drawers must provide the following functions, with correct signatures:
| Method Signature | Description |
|---|---|
addClass(className: string) => void | Adds a class to the root element. |
removeClass(className: string) => void | Removes a class from the root element. |
hasClass(className: string) => boolean | Returns boolean indicating whether element has a given class. |
addBodyClass(className: string) => void | Adds a class to the body. |
removeBodyClass(className: string) => void | Removes a class from the body. |
hasNecessaryDom() => boolean | Returns boolean indicating whether the necessary DOM is present (namely, the mdc-temporary-drawer__drawer drawer container). |
registerInteractionHandler(evt: string, handler: EventListener) => void | Adds an event listener to the root element, for the specified event name. |
deregisterInteractionHandler(evt: string, handler: EventListener) => void | Removes an event listener from the root element, for the specified event name. |
registerDrawerInteractionHandler(evt: string, handler: EventListener) => void | Adds an event listener to the drawer container sub-element, for the specified event name. |
deregisterDrawerInteractionHandler(evt: string, handler: EventListener) => void | Removes an event listener from drawer container sub-element, for the specified event name. |
registerTransitionEndHandler(handler: EventListener) => void | Registers an event handler to be called when a transitionend event is triggered on the drawer container sub-element element. |
deregisterTransitionEndHandler(handler: EventListener) => void | Deregisters an event handler from a transitionend event listener. This will only be called with handlers that have previously been passed to registerTransitionEndHandler calls. |
registerDocumentKeydownHandler(handler: EventListener) => void | Registers an event handler on the document object for a keydown event. |
deregisterDocumentKeydownHandler(handler: EventListener) => void | Deregisters an event handler on the document object for a keydown event. |
getDrawerWidth() => number | Returns the current drawer width, in pixels. |
setTranslateX(value: number) => void | Sets the current position for the drawer, in pixels from the border. |
updateCssVariable(value: string) => void | Sets a CSS custom property, for controlling the current background opacity when manually dragging the drawer. |
getFocusableElements() => NodeList | Returns the node list of focusable elements inside the drawer. |
saveElementTabState(el: Element) => void | Saves the current tab index for the element in a data property. |
restoreElementTabState(el: Element) => void | Restores the saved tab index (if any) for an element. |
makeElementUntabbable(el: Element) => void | Makes an element untabbable. |
notifyOpen() => void | Dispatches an event notifying listeners that the drawer has been opened. |
notifyClose() => void | Dispatches an event notifying listeners that the drawer has been closed. |
isRtl() => boolean | Returns boolean indicating whether the current environment is RTL. |
isDrawer(el: Element) => boolean | Returns boolean indicating whether the provided element is the drawer container sub-element. |
External frameworks and libraries can use the following utility methods when integrating a component.
Remap touch events to pointer events, if the browser doesn't support touch events.
Choose the correct transform property to use on the current browser.
Determine whether the current browser supports CSS properties.
Determine whether the current browser supports passive event listeners, and if so, use them.
Save the tab state for an element.
Restore the tab state for an element, if it was saved.
react-sidebar is a library for creating sidebars in React applications. It provides a flexible and customizable way to implement sidebars, but it does not follow Material Design guidelines as strictly as @material/drawer.
react-burger-menu is another React library for creating off-canvas menus. It offers a variety of animations and styles for the sidebar, making it more versatile in terms of design compared to @material/drawer.
rc-drawer is a drawer component for React that supports both left and right side drawers. It is highly customizable and can be used in various types of web applications, but it does not provide the same level of built-in Material Design styling as @material/drawer.
FAQs
The Material Components Web drawer component
The npm package @material/drawer receives a total of 375,495 weekly downloads. As such, @material/drawer popularity was classified as popular.
We found that @material/drawer demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 15 open source maintainers collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Learn the essential steps every developer should take to stay secure on npm and reduce exposure to supply chain attacks.

Security News
Experts push back on new claims about AI-driven ransomware, warning that hype and sponsored research are distorting how the threat is understood.

Security News
Ruby's creator Matz assumes control of RubyGems and Bundler repositories while former maintainers agree to step back and transfer all rights to end the dispute.