feat: add navigation rail - #5106
Open
marius-ck wants to merge 5 commits into
Open
Conversation
…into mariuspasca-callstack-feat/add-navigation-rail
marius-ck
marked this pull request as ready for review
September 8, 2026 12:08
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
Paper has no Material Design 3 navigation rail. The closest existing option is
Drawer.CollapsedItem, which only covers the collapsed icon layout, has no expanded state, no header slot, and no modal presentation — so apps targeting medium and large window classes have to hand-roll side navigation.This PR adds
NavigationRailwith the full MD3 behaviour:expandedprop rather than by swapping components.expandedWidthis clamped to the spec range.emphasized). The indicator grows 32dp → 56dp and stretches to cover icon and label, the icon stays at a fixed leading offset so it never shifts, and the stacked and row labels cross-fade. Every item inherits this from context, so new destinations need no extra wiring.overlaymode. The rail keeps its collapsed footprint in the layout and the expanded panel floats above the content behind a scrim, for layouts that can't afford to reflow.onDismissfires on scrim press.NavigationRail.Modal. A standalone expanded rail on its own layer, sliding in over 400ms (emphasizedDecelerate) and out over 200ms (emphasizedAccelerate), RTL-aware, with scrim, hardware back and escape handling. It stays mounted through the exit so the slide-out actually plays.animatedflag. Opts out of every rail animation in one place, including the items and the modal's mount timing.role="tab"witharia-selected/aria-disabled, labels drive the accessibility name, hidden label copies arearia-hidden, a focus ring appears on keyboard focus only, and reduced motion skips layout motion while keeping fades.surfacecollapsed,surfaceContainerexpanded,secondaryContainer/onSecondaryContainerfor the active indicator and icon,scrimfor the backdrop. Spec values live in a per-componenttokens.tsalongside autils.ts, matching FAB and Switch.docs/6.x/docs/guides/migration.mdgains a Drawer section pointingDrawer.CollapsedItemusers at the new component, and the docs site picks up the three components plus their theme colors.Related issue
No existing issue. The gap: MD3 lists the navigation rail as the primary navigation pattern for medium and expanded window classes, and Paper ships no equivalent —
Drawer.CollapsedItemcovers only the collapsed rail, with no expanded rows, header slot, modal variant, or transition between states.Test plan
Automated
New suites under
src/components/__tests__/NavigationRail/cover render snapshots for both layouts, the collapsed and clamped widths, the overlay footprint and scrim fade plus dismiss, the label swap between layouts, the modal's slide-out-before-unmount and its instant unmount whenanimated={false}, scrim dismissal, active-icon and indicator state, accessibility names, press and disabled behaviour, badges, and theresolveItemColors/clampExpandedWidthhelpers.Manual — example app, "Navigation Rail" screen
surfaceContainer, each indicator grows and stretches over its label, labels cross-fade from beneath the icon to beside it, the header FAB expands to show its label, and the toggle icon cross-fades. Collapse and confirm it reverses cleanly with no text wrapping or jumping mid-transition.https://app.notion.com/p/callstack/Add-Navigation-Rail-37a5d027c0f881cc93c4d8195e84e175?v=3285d027c0f880a68ccb000c1ce3c56e&source=copy_link
https://m3.material.io/components/navigation-rail/overview