Side nav
Application navigation with a compact rail, recursive groups, and native links.
Import SideNav from @commenda/pathfinder/side-nav. The application owns routes, active destination, permissions and persistence. No workspace providers, cookies or global shortcuts are required.
API reference
| Prop | Type | Behavior |
|---|---|---|
labelRequired | string | Required navigation landmark name |
sectionsRequired | readonly SideNavSection[] | IDs, optional label/collapsible, recursive items |
activeIdRequired | string|null | Current destination; receives aria-current=page |
collapseConfig | ObjectView fields · 2 shapes | { value, onValueChange } or { defaultValue?, onValueChange? }; false initially |
expansionConfig | ObjectView fields · 2 shapes | Section and group IDs; collapsible sections start open |
header | | ReactNode
| ((
collapsed: boolean
) => ReactNode) | Slots can adapt to the rail |
footer | | ReactNode
| ((
collapsed: boolean
) => ReactNode) | Slots can adapt to the rail |
modeConfig | SegmentedControlProps | Optional view-mode switch; app supplies matching sections |
renderLink | (
props: React.ComponentPropsWithRef<'a'>
) => React.ReactElement | Next Link integration; item renderer takes precedence |
className | string | Root nav classes; parent supplies available height |
An item has id, label, icon, optional count, unread, and disableConfig: { isDisabled, reason? }. Its kind distinguishes link with linkConfig, action with onAction, or group with recursive children and optional landing linkConfig. A landing link and its chevron are distinct targets. A group without a landing link expands on activation.
Keep section and item IDs stable and globally distinct. linkConfig supports href, target, rel, and a ref-forwarding render. Renderers must preserve supplied accessibility props, handlers and refs. Actions and links are mutually exclusive. Counts and unread state stay accessible in the rail.
Collapsed rail
Expanded width is 208px; the rail is 56px. Rows are 28px, icons 16px. In the rail, group activation expands navigation to reveal its children; groups with a destination preserve that link, and the Expand sidebar control reveals their descendants. Header/footer render functions prevent a long organization name from overflowing a rail.
Controlled state
Expansion and collapse are independent of the active route. The app may persist them per user; Pathfinder does not read browser storage. Overflow fades follow actual scroll position. Use an app-owned mobile navigation surface when the persistent sidebar does not fit; the component does not guess viewport breakpoints or mutate routes. Chat conversation history remains a separately composed pattern. Read the hierarchy rules.
Design rules
Figma guidance and reviewed implementation decisions for this component. Rule IDs remain stable for source comments and AI references.
Side navigation
- NAV-001: Expanded 208px, rail 56px, pearl100 background, 12px inset, 24px section gaps. Header mark/wordmark and collapse control; optional Home/Chat SegmentedControl; footer account composition. Rows 28px, radius 6, horizontal inset 8, gap 12, icons 16.
- NAV-002: Label/13 pearl900; icon pearl800. Hover pearl200, selected pearl300, selected label1000 and icon blue700. The landing link and expansion chevron share one continuous hover/selected row surface. Weight never changes. The docs prose mentions selected 200, but the reviewed component 714:15 uses 300; the implementation follows the component. Count Label/12, optional unread dot; rail uses tooltip and accessible metadata.
- NAV-003: Stable globally distinct IDs, one active destination, real anchors, separate group chevrons. Routing, auth, persistence and fetching belong to the application. Collapse retains group/section state. Chat history is a separate composed pattern; do not embed an application’s routes or conversation API in SideNav.
- NAV-004: Scroll fades match CommendaNavbar: 48px from the Soft Pearl 100 surface (#FCFBF8) to transparent, appearing only at overflowing edges. The parent supplies available height. No global keyboard shortcut, cookie or workspace provider is installed by the component.