Skip to content

ExpressiveCSS

Browse documentation

Navigation rail

Switch between UI views on mid-sized devices.

View as Markdown

A nav.navigation-rail holds 3 to 7 destinations plus an optional FAB. Put it in the same place on every screen. Use it in medium, expanded, large, or extra-large windows.

Collapsed is 96dp with the icon above the label. Add expanded for a 220 to 360dp rail with icon and label on one row and an extended FAB. The menu button toggles that class (AutoInit() starts it). On compact windows, an expanded rail is modal. It shows a scrim, and Escape or a tap on the scrim collapses it. Add modal to keep that overlay at every breakpoint.

Escape closes an open nested menu first. A second Escape collapses the modal rail and returns focus from inside it to the rail toggle, unless a close callback moves focus elsewhere.

Compact windows that need persistent destinations still use a navigation bar. Split larger hierarchies into peer categories and a separate page-level list.

Collapsed

This is the default. It is 96dp wide, with the icon above the label and the selected pill behind the icon. The FAB is icon-only. Offset the rest of the page by --md-comp-nav-rail-collapsed-width.

<nav class="navigation-rail" aria-label="Main">
  <button type="button" aria-label="Menu">
    <span class="material-symbols" aria-hidden="true">menu</span>
  </button>
  <a class="button" href="/compose">
    <span class="material-symbols" aria-hidden="true">edit</span>
    <span>Label</span>
  </a>
  <a href="/" aria-current="page">
    <span class="material-symbols" aria-hidden="true">star</span>
    Label
  </a>
  <a href="/two" aria-label="Starred, 3 unread">
    <span class="material-symbols" aria-hidden="true">star<span class="badge">3</span></span>
    Label
  </a>
</nav>

Expanded

Add expanded. Destinations become a row: icon, then label, with the selected pill around both. The FAB grows into an extended button. Section headings show only in this layout.

Expanding and collapsing run on the default spatial spring. --md-comp-nav-rail-motion and --md-comp-nav-rail-motion-duration read --md-sys-motion-spring-default-spatial and its duration, so motion="expressive" lets the rail overshoot its width slightly before it settles. The rail grows from its docked edge, so nothing behind it is uncovered.

<nav class="navigation-rail expanded" aria-label="Main">
  …
  <h3>Section Header</h3>
  <a href="/other">
    <span class="material-symbols" aria-hidden="true">star</span>
    Label
  </a>
</nav>
@media (width >= 600px) {
  body {
    padding-left: var(--md-comp-nav-rail-collapsed-width);
  }
  body:has(.navigation-rail.expanded) {
    padding-left: var(--md-comp-nav-rail-expanded-width);
  }
}

Side panel

A destination can open a panel of more links beside the rail. Make the destination a <button> with popovertarget and put its .navigation-rail-panel popover right after it. The panel docks against the rail's edge at full window height.

A click toggles the panel. The browser handles light dismiss, Escape and the button's expanded state. With a mouse, hovering the destination opens the panel, and it closes again once the pointer leaves both. Clicking a hovered destination keeps its panel open.

Group links under a <details>. Its <summary> is the dropdown row, and the links after it are indented. Mark the current page with aria-current="page".

<nav class="navigation-rail" aria-label="Main">
  …
  <button type="button" popovertarget="components-panel">
    <span class="material-symbols" aria-hidden="true">widgets</span>
    Components
  </button>
  <div id="components-panel" class="navigation-rail-panel" popover>
    <a href="/components" aria-current="page">Components overview</a>
    <a href="/app-bars">App bars</a>
    <details>
      <summary>Date &amp; time pickers</summary>
      <a href="/date-pickers">Date pickers</a>
      <a href="/time-pickers">Time pickers</a>
    </details>
  </div>
</nav>

Tokens

Token Default
--md-comp-nav-rail-collapsed-width96px
--md-comp-nav-rail-expanded-width280px (clamped between 220 and 360)
--md-comp-nav-rail-icon-size24px
--md-comp-nav-rail-indicator-width56px
--md-comp-nav-rail-fab-size56px
--md-comp-nav-rail-panel-width256px

No matching pages

  • 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.

    Default source: Mist Iris.

    ExpressiveCSS presets: Lagoon, Harbor, Breeze, Cobalt, Iris.

    Bold

    Soft

    Mist

    Glow