NavigationRail

Navigation rails let people switch between UI views on mid-sized devices.

One family, one doc

NavigationRail, NavigationRailItem, and NavigationRailSection form a single family. This page is their shared documentation; each component keeps its own API reference:

NavigationRail provides primary navigation for an app on mid-sized devices. Compose it with NavigationRailItem children; optionally include a Fab and NavigationRailSection labels.

Alignment

alignment distributes items either from the top ("top", default) or spread across the rail’s full height ("middle").

Extended rail

Toggling the extended mode reveals labels and any NavigationRailSection. Control it with extended/onExtendedChange (extendedChange in Angular, or bind:extended in Svelte), or leave it uncontrolled with defaultExtended. A Fab placed as a direct child is hoisted into the rail’s header; Angular does not clone it, so pass its extended state explicitly.

Controlled selection

Use selectedItem to control the selected item. React exposes a raw setSelectedItem dispatcher; Angular follows this repository’s output convention with selectedItemChange ([(selectedItem)] also works). Svelte uses bind:selectedItem or selectedItem with onSelectedItemChange. onItemSelected/itemSelected notifies with the resulting index, label, and icon.

footer pins arbitrary content — an account menu, a sign-out button — below the item list, without wrapping NavigationRail in a custom layout. In Angular, add a footer attribute to the projected element.

Composition

  • NavigationRailItem is a single destination; it renders a link when href is set, otherwise a button. The selected item exposes aria-current="page".
  • NavigationRailSection is a non-interactive label that groups the items following it; it, and any item placed after it, only render while the rail is extended.
  • A Fab placed as a direct child is hoisted into the rail’s header and collapses/expands with the rail.

Angular differences

  • NavigationRailItem’s label reveal (width/height + opacity) is driven by a shared @udixio/core/dom Motion controller, identical in both frameworks.
  • Angular does not clone the projected Fab; bind its extended input explicitly from the same state driving the rail (see the example above).