Use Section Rail to navigate a long page, case study, or multi-step flow. The active line reflects the section in view and can reveal labels or a context card for nearby sections.
Install
Basic usage
Examples
Use scroll mode for heading anchors in a document. Use controlled mode when the active section is managed outside the rail.
API
| Property | Type | Default | Description |
|---|
items | SectionRailItem[] | required | The sections represented by the rail, in document order. |
mode | "scroll" | "controlled" | "scroll" | `"scroll"` resolves the active item from the page; `"controlled"` leaves it to `activeId` / `onActiveChange`. |
activeId | string | undefined | Active item id for controlled usage. |
defaultActiveId | string | undefined | Initial active item id for uncontrolled usage. |
onActiveChange | (id: string) => void | undefined | Called whenever the active item changes. |
showLabels | "hidden" | "always" | "active" | "hover" | "hidden" | When labels sit next to the rail on fine pointers. Defaults to `"hidden"` because the context card already names the section, so an inline label would only appear underneath it. Coarse pointers, which never get a card, always show labels. |
activeIndicator | "dot" | "fill" | "progress" | "progress" | How the active item is marked. `"progress"` fills the active line from the section's own scroll position. |
orientation | "vertical" | "horizontal" | "vertical" | Direction the rail runs in. |
side | "left" | "right" | "right" | Which edge the rail is anchored to, which flips label and card placement. |
scrollOffset | number | 96 | Pixels of fixed-header compensation used when scrolling to a section. |
getSectionElement | (id: string) => HTMLElement | null | undefined | Resolves a section element when ids are not real DOM ids. |
scrollRoot | React.RefObject<HTMLElement | null> | undefined | Scrolling element the sections live in. Defaults to the page itself. |
showPreview | "never" | "hover" | "focus" | "hover-and-focus" | "hover-and-focus" | When the context card appears. Cards never appear on coarse pointers. |
ariaLabel | string | "Section navigation" | Accessible name for the rail's landmark. |
className | string | undefined | Additional classes for the rail root. |
lineClassName | string | undefined | Additional classes for each rail line. |
labelClassName | string | undefined | Additional classes for the item labels. |
previewClassName | string | undefined | Additional classes for the context card surface. |
Accessibility
Scroll mode uses real anchor links, while controlled mode uses buttons with the current section exposed to assistive technology. Coarse pointers receive visible labels instead of hover-only targets.
Styling
Use the context-card options for additional editorial detail. Reduced-motion preferences simplify the rail and scroll behavior.
Found a bug or need help using this component? Open an issue on GitHub.
License & Usage
Sona UI is available under the MIT license. You may use, modify, and distribute this component in personal and commercial projects.