Skip to main content brightness_auto motion_photos_off palette download more_vert
toc

Navigation Rail

A navigation rail lets people switch between top-level destinations on larger windows, and expands to show full labels.

mail Inbox chat_bubble Chat groups Spaces videocam Meet
<md-gb-nav-rail aria-label="Primary" collapsible>
  <md-gb-nav-rail-item selected href="#inbox">
    <md-gb-icon slot="icon">mail</md-gb-icon>
    Inbox
  </md-gb-nav-rail-item>
  <md-gb-nav-rail-item href="#chat">
    <md-gb-icon slot="icon">chat_bubble</md-gb-icon>
    Chat
  </md-gb-nav-rail-item>
  <md-gb-nav-rail-item href="#spaces">
    <md-gb-icon slot="icon">groups</md-gb-icon>
    Spaces
  </md-gb-nav-rail-item>
  <md-gb-nav-rail-item href="#meet">
    <md-gb-icon slot="icon">videocam</md-gb-icon>
    Meet
  </md-gb-nav-rail-item>
</md-gb-nav-rail>

Install with shadcn/ui: npx shadcn@latest add https://material-web.dev/3.0/r/md-nav-rail.json (setup)

  • Use it in medium windows and larger. On compact windows use a navigation bar instead.
  • Keep three to seven destinations. Add an optional FAB or menu button in the header.
  • Keep it in the same place. The rail stays at the leading edge on every screen of the app.
  • Let it expand. A collapsed rail shows icons and short labels, and an expanded rail shows horizontal items and can replace a navigation drawer.

This component is new in M3 Expressive.

A rail has an optional header, such as a menu button or a FAB, and items. Each item has an icon, a label and an optional badge.

menu edit inbox 3 Inbox send Sent
<md-gb-nav-rail aria-label="Mail">
  <md-gb-icon-button slot="header" aria-label="Open menu"><md-gb-icon>menu</md-gb-icon></md-gb-icon-button>
  <md-gb-fab slot="header" aria-label="Compose"><md-gb-icon>edit</md-gb-icon></md-gb-fab>
  <md-gb-nav-rail-item selected href="#anatomy-inbox">
    <md-gb-icon slot="icon">inbox</md-gb-icon>
    <span slot="badge">3</span>
    Inbox
  </md-gb-nav-rail-item>
  <md-gb-nav-rail-item href="#anatomy-sent">
    <md-gb-icon slot="icon">send</md-gb-icon>
    Sent
  </md-gb-nav-rail-item>
</md-gb-nav-rail>

Give an item an href (and optionally target and rel) to make the destination a link, as in the first example. The item then has the link role and the selected one is marked aria-current="page". Without href an item is a tab that just reports the selection.

Add collapsible to show a built-in menu button in the header that expands and collapses the rail. To use your own button, put it in the header slot and call toggle(), expand() or collapse(). Set expanded to start expanded. The rail fires toggle when it expands or collapses.

mail Inbox send Sent drafts Drafts
<md-gb-nav-rail aria-label="Mail" collapsible expanded>
  <md-gb-nav-rail-item selected>
    <md-gb-icon slot="icon">mail</md-gb-icon>
    Inbox
  </md-gb-nav-rail-item>
  <md-gb-nav-rail-item>
    <md-gb-icon slot="icon">send</md-gb-icon>
    Sent
  </md-gb-nav-rail-item>
  <md-gb-nav-rail-item>
    <md-gb-icon slot="icon">drafts</md-gb-icon>
    Drafts
  </md-gb-nav-rail-item>
</md-gb-nav-rail>

Use the header slot for a menu button and a FAB above the items.

menu edit mail Inbox send Sent
<md-gb-nav-rail aria-label="Mail">
  <md-gb-icon-button slot="header" aria-label="Open menu">
    <md-gb-icon>menu</md-gb-icon>
  </md-gb-icon-button>
  <md-gb-fab slot="header" label="Compose">
    <md-gb-icon>edit</md-gb-icon>
  </md-gb-fab>
  <md-gb-nav-rail-item selected>
    <md-gb-icon slot="icon">mail</md-gb-icon>
    Inbox
  </md-gb-nav-rail-item>
  <md-gb-nav-rail-item>
    <md-gb-icon slot="icon">send</md-gb-icon>
    Sent
  </md-gb-nav-rail-item>
</md-gb-nav-rail>

Set alignment to top (the default), center or bottom to place the items along the rail.

home Home search Search settings Settings
<md-gb-nav-rail aria-label="Primary" alignment="center">
  <md-gb-nav-rail-item selected>
    <md-gb-icon slot="icon">home</md-gb-icon>
    Home
  </md-gb-nav-rail-item>
  <md-gb-nav-rail-item>
    <md-gb-icon slot="icon">search</md-gb-icon>
    Search
  </md-gb-nav-rail-item>
  <md-gb-nav-rail-item>
    <md-gb-icon slot="icon">settings</md-gb-icon>
    Settings
  </md-gb-nav-rail-item>
</md-gb-nav-rail>

Set badge on an item to show a count, or badge="dot" for a small dot.

mail Inbox chat_bubble Chat
<md-gb-nav-rail aria-label="Mail">
  <md-gb-nav-rail-item selected badge="4">
    <md-gb-icon slot="icon">mail</md-gb-icon>
    Inbox
  </md-gb-nav-rail-item>
  <md-gb-nav-rail-item badge="dot">
    <md-gb-icon slot="icon">chat_bubble</md-gb-icon>
    Chat
  </md-gb-nav-rail-item>
</md-gb-nav-rail>

Add secondary to an item that should show only while the rail is expanded, such as a less important destination.

mail Inbox delete Trash
<md-gb-nav-rail aria-label="Mail" collapsible expanded>
  <md-gb-nav-rail-item selected>
    <md-gb-icon slot="icon">mail</md-gb-icon>
    Inbox
  </md-gb-nav-rail-item>
  <md-gb-nav-rail-item secondary>
    <md-gb-icon slot="icon">delete</md-gb-icon>
    Trash
  </md-gb-nav-rail-item>
</md-gb-nav-rail>

Add modal so the expanded rail opens over the content with a scrim. Add hide-when-collapsed to take the collapsed rail out of the layout entirely; the app's menu button then calls toggle() to show it. On Android, the back gesture collapses a modal rail.

mail Inbox send Sent
<md-gb-nav-rail aria-label="Mail" modal collapsible>
  <md-gb-nav-rail-item selected>
    <md-gb-icon slot="icon">mail</md-gb-icon>
    Inbox
  </md-gb-nav-rail-item>
  <md-gb-nav-rail-item>
    <md-gb-icon slot="icon">send</md-gb-icon>
    Sent
  </md-gb-nav-rail-item>
</md-gb-nav-rail>

Add divider to draw a line at the rail's edge, elevated to lift it above scrolling content, and narrow to use the 80dp collapsed width.

home Home search Search
<md-gb-nav-rail aria-label="Primary" narrow divider>
  <md-gb-nav-rail-item selected>
    <md-gb-icon slot="icon">home</md-gb-icon>
    Home
  </md-gb-nav-rail-item>
  <md-gb-nav-rail-item>
    <md-gb-icon slot="icon">search</md-gb-icon>
    Search
  </md-gb-nav-rail-item>
</md-gb-nav-rail>
  • Give the rail an aria-label such as "Primary navigation".
  • Without links the rail is a tab list and its items are tabs, with exactly one selected. Tab moves focus into the rail, the arrow keys move between items, and Enter and Space select one.
  • When the items have an href the rail is a navigation landmark of links and the selected one is aria-current="page". Enter follows a link; Space doesn't.
  • Every item needs a visible label, which is also its accessible name.
  • Give a menu button in the header an aria-label, such as "Open menu".
  • A modal rail collapses on Escape and when the scrim is pressed. Keep the menu button available as the single-pointer alternative to swiping it closed.
  • Disabled items leave the tab order.
Material Design 3Spec checked50% tokens

134 of 311 buildable spec units are tested, 11 are excluded with a written reason and 0 are uncovered (the target is 0). 46 of 92 token declarations match the spec (50%), and 46 have no spec token.

BaselineWidely availableChrome 124Edge 124Firefox 125Safari 17.4

The component’s own CSS and JavaScript rely only on web platform features that are Baseline widely available: it works in Chrome 124, Edge 124, Firefox 125, Safari 17.4 and later.

Newer features it uses where the browser has them (progressive enhancements):

WAI-ARIAaxe and ARIA 1.3 passButtonTabs

Roles the component renders: button (opens in a new tab), navigation (opens in a new tab), tablist (opens in a new tab).

Follows the WAI-ARIA Authoring Practices: Button (opens in a new tab), Tabs (opens in a new tab).

2 rendered states run through axe-core and the WAI-ARIA 1.3 role and attribute rules in a real browser, with no known gaps.

Lighthouse97 · 100 · 100 · 100
  • Performance
  • Accessibility
  • Best practices
  • SEO

Audits under 90:

  • Largest Contentful Paint
  • Largest Contentful Paint element
  • Elements with visible text labels do not have matching accessible names.
  • Eliminate render-blocking resources
  • Minify JavaScript
  • Reduce unused CSS
  • Enable text compression
  • Document request latency
  • Network dependency tree
  • Render blocking requests

Lighthouse 12.8.2 (desktop, 2026-11-08) on the component alone: its first example on a page of its own, without this site's shell. The modules are the development build (not bundled or minified), so the performance score is indicative.

A Material Design navigation rail custom element.

Property Attribute Type Default
alignment
Vertical alignment of items ('top', 'center', or 'bottom').
alignment NavRailAlignment 'top'
autoSelect
Whether or not to automatically select a tab when it is focused.
autoselect boolean false
collapsible
Whether the navigation rail renders a built-in expand/collapse menu button in the header when no toggle button is slotted into slot="header".
collapsible boolean false
divider
Whether a vertical divider marks the edge of the rail next to the app's content.
divider boolean false
elevated
Whether the rail is elevated to level 1, to distinguish it from content that scrolls underneath it.
elevated boolean false
expanded
Whether the navigation rail is expanded to show horizontal items.
expanded boolean false
hideWhenCollapsed
Hide when collapsed (navigation-rail.md): the collapsed rail is not shown and takes no space, so the body content fills in. The expanded rail (always modal in this mode) appears over the content when the app's menu button calls expand() or toggle(); keep that menu button accessible.
hide-when-collapsed boolean false
itemLayout
The layout orientation of items ('vertical' or 'horizontal').
item-layout NavRailItemLayout 'vertical'
modal
Whether the expanded navigation rail is modal: it opens over the content with a scrim, with modal elevation and shape.
modal boolean false
narrow
Whether the collapsed rail uses the narrow width (md.comp.nav-rail.collapsed.narrow.container.width, 80dp).
narrow boolean false
selectedIndex
The 0-based index of the currently active navigation rail item. Alias for selectedTabIndex.
selected-index number
selectedTabIndex
The index of the currently selected tab.
selectedtabindex number
Slot Description
default Used to display navigation rail items (md-gb-nav-rail-item).
header Used to display optional header controls (menu button, FAB).
Event Description
change
Event
Fired when the selected item changes.
toggle
CustomEvent<{expanded: boolean, reason?: string}>
Fired when the expanded state is toggled.
Method Description
collapse
() => void
Collapses the navigation rail.
expand
() => void
Expands the navigation rail.
handleBack
() => Promise<void>
Handles a back request (the Android back gesture or button) on the modal expanded rail: plays the predictive back motion, then collapses the rail. Call it for an in-app back control that should behave like the system back. Resolves after the back motion.
toggle
(force?: boolean) => boolean
Toggles the expanded state of the navigation rail.
Part Description
::part(header) The navigation rail's header container.
::part(items) The navigation rail's items container.
::part(menu-button) The built-in expand/collapse menu button when collapsible.
::part(nav-rail) The navigation rail's root container.
::part(scrim) The modal rail's scrim, while expanded. A modal rail expands over the content with a scrim, like Compose ModalWideNavigationRail. Clicking the scrim, pressing Escape or swiping the rail toward its edge collapses it. The scrim (and the menu button of a collapsible rail) are the single-pointer alternatives to the swipe. While a modal rail is expanded, focus moves into it, Tab stays inside it, page scrolling is locked, and focus returns to the previous element when it collapses. The toggle event's detail.reason says why a modal rail collapsed (escape, back, scrim or swipe). Predictive back applies to the modal expanded rail (navigation-rail.md): while it is expanded the rail listens for back requests with a CloseWatcher (the Android back gesture or button, and Escape), falling back to Escape on the document where CloseWatcher is missing. A back request plays the predictive back motion (the rail pops off its edge, Compose ModalWideNavigationRail scales) and collapses the rail. A FAB (md-gb-fab with a label) in the header is an extended FAB while the rail is expanded and an icon FAB while it is collapsed.
Property Description
--collapsed-item-vertical-space
--collapsed-narrow-container-width
--collapsed-top-space
--container-color
--container-elevation
--container-shape
--container-vertical-padding
--container-width
--expanded-container-color
--expanded-container-width-maximum
--expanded-container-width-minimum
--expanded-modal-container-color
--expanded-top-space
--header-space-minimum
--item-active-focused-icon-color
--item-active-focused-label-text-color
--item-active-hovered-icon-color
--item-active-hovered-label-text-color
--item-active-icon-color
--item-active-indicator-color
--item-active-indicator-height
--item-active-indicator-shape
--item-active-indicator-width
--item-active-label-text-color
--item-active-pressed-icon-color
--item-active-pressed-label-text-color
--item-active-state-layer-color
--item-container-height
--item-container-vertical-space
--item-full-width-leading-space
--item-full-width-trailing-space
--item-horizontal-active-indicator-height
--item-horizontal-active-indicator-width The expanded destinations' pill width: fit-content (default) hugs the icon and label; 100% takes the destination's width.
--item-horizontal-icon-label-space
--item-icon-size
--item-inactive-focused-icon-color
--item-inactive-focused-label-text-color
--item-inactive-hovered-icon-color
--item-inactive-hovered-label-text-color
--item-inactive-icon-color
--item-inactive-label-text-color
--item-inactive-pressed-icon-color
--item-inactive-pressed-label-text-color
--item-inactive-state-layer-color
--item-label-text-font
--item-label-text-font-axes
--item-label-text-font-tracking
--item-outer-space
--item-vertical-icon-label-space
--item-vertical-leading-space
--item-vertical-trailing-space
--modal-container-elevation
--modal-container-shape
--modal-scrim-color
--motion-duration
--motion-easing

A Material Design navigation rail item custom element.

Property Attribute Type Default
active
Whether the navigation rail item is active. Alias for selected. TODO: replace reflected [active] with :state(selected)
active boolean
badge
Optional badge text (or 'dot' / 'true' for a small dot badge).
badge string ''
disabled
Whether the navigation rail item is disabled.
disabled boolean false
href
The URL the destination links to. The item is then a link (role link, aria-current="page" while selected) instead of a tab.
href string ''
itemLayout
The layout orientation of the item ('vertical' or 'horizontal').
item-layout NavRailItemLayout 'vertical'
label
Optional label text if not provided via default slot.
label string ''
rel
The link's rel attribute, when href is set.
rel string ''
secondary
Whether the destination is secondary: it shows only while the rail is expanded.
secondary boolean false
tabpanel
ID of the associated md-aria-tabpanel element.
tabpanel string
target
Where to open the linked href, e.g. _blank.
target "" "_blank"
unfilledIcon
Whether the icon has no filled style. The active destination then uses the semibold icon weight instead of the filled icon.
unfilled-icon boolean false
Slot Description
default Used to display the item's label text.
badge Used to display a custom badge on the item's icon.
icon Used to display the item's icon (md-gb-icon).
Method Description
click
() => void
Activates the destination: follows its link, else clicks the tab.
Part Description
::part(indicator) The active indicator / icon container element.
::part(label) The label text container element.
::part(nav-rail-item) The navigation rail item's presentational container.
Install Material Web 3.0

Your browser did not offer to install the docs as an app. Install them from the browser instead:

Close
Send feedback
Bug Documentation Idea

Opens a new GitHub issue for material-components/material-web in a new tab, with this filled in.

Cancel Open issue