NavigationDrawer

NavigationDrawer

A slide-out menu, or a fixed sidebar on Expanded and wider screens.

This is a slide-out menu. Nest <details> / <summary> for nested sections — the documentation sidebar uses that. On Compact and Medium windows this same drawer slides over the page.

An overlay sidenav is a modal <dialog>. The framework wraps your <ul class="navigation-drawer">; Escape and a tap on the backdrop close it. A navigation-drawer-fixed drawer stays open from Expanded as CSS — no resize listener, no overlay.

The sidenav HTML must not sit inside the app bar’s <nav>. Put a navigation-drawer-trigger anywhere and set data-target to the navigation drawer’s id. AutoInit() starts every .navigation-drawer except those marked no-autoinit.

<nav aria-label="Main">
  <ul id="slide-out" class="navigation-drawer">
    <li>
      <div class="user-view">
        <div class="background">
          <img src="images/office.jpg" alt="">
        </div>
        <a href="#user" aria-label="Profile"><img class="circle" src="images/portrait.jpg" alt=""></a>
        <a href="#name"><span class="name">John Doe</span></a>
        <a href="#email"><span class="email">jdoe@example.com</span></a>
      </div>
    </li>
    <li><a href="#!"><span class="material-symbols" aria-hidden="true">cloud</span>First Link With Icon</a></li>
    <li><a href="#!">Second Link</a></li>
    <li><div class="divider"></div></li>
    <li><span class="subheader">Subheader</span></li>
    <li><a href="#!">Third Link</a></li>
  </ul>
</nav>
<button type="button" data-target="slide-out" class="button text circle navigation-drawer-trigger" aria-label="Menu"><span class="material-symbols" aria-hidden="true">menu</span></button>

Initialization

The IIFE bundle exposes Expressive.NavigationDrawer. Call init yourself when you need options other than the defaults, or let Expressive.AutoInit() start every .navigation-drawer.

document.addEventListener('DOMContentLoaded', function() {
  const elems = document.querySelectorAll('.navigation-drawer');
  const instances = Expressive.NavigationDrawer.init(elems, {
    // specify options here
  });
});

Options

Name Type Default Description
edge String 'left' Side of the screen. 'left' or 'right'. The constructor adds right-aligned when the edge is right.
draggable Boolean true Allow swipe gestures to open and close. Drag is disabled while the navigation drawer is fixed on Expanded and wider windows.
dragTargetWidth String '10px' Width of the screen-edge strip where a drag can start.
onOpenStart Function null Called when the navigation drawer starts opening.
onOpenEnd Function null Called when the navigation drawer finishes opening.
onCloseStart Function null Called when the navigation drawer starts closing.
onCloseEnd Function null Called when the navigation drawer finishes closing.

Methods

All methods are called on the plugin instance. You can get the instance like this:
const instance = Expressive.NavigationDrawer.getInstance(elem);
.open();

Opens the navigation drawer.

instance.open();
.close();

Closes the navigation drawer.

instance.close();
.destroy();

Destroy the plugin instance, unwrap the dialog host, and remove the drag target and event handlers.

instance.destroy();

Properties

Name Type Description
el Element The DOM element the plugin was initialized with.
options Object The options the instance was initialized with.
isOpen Boolean Whether the overlay drawer is open. Stays false while a fixed sidenav is docked on Expanded and wider windows.
isFixed Boolean Whether the element has navigation-drawer-fixed.
isDragged Boolean Whether the navigation drawer is being dragged.

Close Trigger

Add navigation-drawer-close to an element inside the navigation drawer. A click on that element closes an overlay sidenav. That is useful in a single-page app where the page does not reload. It does nothing while the navigation drawer is fixed on Expanded and wider windows.

<nav aria-label="Main">
  <ul id="slide-out" class="navigation-drawer">
    <li><button type="button" class="navigation-drawer-close">Clicking this will close NavigationDrawer</button></li>
  </ul>
</nav>
<button type="button" data-target="slide-out" class="button text circle navigation-drawer-trigger" aria-label="Menu"><span class="material-symbols" aria-hidden="true">menu</span></button>

Variations

Right edge

Pass edge: 'right'. Mark the element no-autoinit if you initialize it yourself, otherwise AutoInit would start it on the left.

Expressive.NavigationDrawer.init(document.querySelector('#slide-out-right'), {
  edge: 'right'
});
Nested sections

Nest <details> for a section that opens in place. Same name on several details is an accordion. The documentation sidebar uses this for Foundations, Structure, Components, and Forms.

<nav aria-label="Main">
  <ul id="slide-out" class="navigation-drawer">
    <li><a href="#!">First Sidebar Link</a></li>
    <li>
      <details name="docs-nav">
        <summary>
          <span class="material-symbols" aria-hidden="true">palette</span>
          Foundations
        </summary>
        <ul>
          <li><a href="#!">Color</a></li>
          <li><a href="#!">Typography</a></li>
        </ul>
      </details>
    </li>
  </ul>
</nav>
Fixed HTML Structure

Add navigation-drawer-fixed so the navigation drawer stays open from Expanded (840px and up) and slides away on smaller ones. That dock is CSS, not a JavaScript open(). The documentation sidebar on the left is this pattern.

<nav aria-label="Main">
  <ul id="slide-out" class="navigation-drawer navigation-drawer-fixed">
    <li><a href="#!">First Sidebar Link</a></li>
    <li><a href="#!">Second Sidebar Link</a></li>
  </ul>
</nav>
<button type="button" data-target="slide-out" class="button text circle navigation-drawer-trigger" aria-label="Menu"><span class="material-symbols" aria-hidden="true">menu</span></button>

Offset the rest of the page by the navigation drawer width. The width token is --md-comp-nav-drawer-width (alias of --md-comp-nav-drawer-width, 300px). Put the padding on header, main, and footer.

@media (width >= 840px) {
  header, main, footer {
    padding-left: var(--md-comp-nav-drawer-width);
  }
}
  • Source color

    The seed every generated ramp derives from. Pick one and browse the docs — the whole theme follows. Error does not: it is a fixed hue.