Sidebar · TopBar Composition

The app shell: navigation down the side, context across the top. Both are slot-driven, because every product disagrees about what belongs in its chrome.

Usage

Updated 4 minutes ago

Overview lives here.

tsx
<Sidebar  sections={sections}  collapsed={collapsed}  onCollapsedChange={setCollapsed}  header={<Logo />}  footer={<Avatar name={user.name} />}/>
<TopBar title={<Breadcrumb items={trail} />} center={<Search />} actions={<Actions />} />

Submenus

An item with items is a disclosure rather than a destination: it expands in place, its children indent against a rail, and a child being active keeps the parent open and marked.

Collapsed is still navigable

Collapsing hides the labels visually and keeps them in the accessible name, so a screen reader still reads "Invoices" where a sighted user sees only an icon. Hovering or focusing a rail item opens a flyout carrying that label — and, for a parent, its whole submenu — so a collapsed rail stays readable instead of becoming a column of guesses.

Do

Mark the active item with active — it sets aria-current='page', which is how the current page is announced.

Don't

Put more than two levels of navigation in the sidebar; the third level belongs on the page.

Props

PropTypeDefaultNotes
sectionsNavSection[]Each has an optional title and its items: label, icon, href or onClick, active, adornment, items.
item.itemsNavItem[]One level of children. The parent becomes a disclosure, and collapsed it becomes a flyout.
header / footerReactNodeBrand at the top, account at the bottom. Both are yours.
collapsed / onCollapsedChangeboolean | fnControlled. Omit the handler and the toggle button disappears.
TopBar title / subtitleReactNodeA string, or a Breadcrumb trail.
TopBar center / actionsReactNodeSearch in the middle, controls at the end.
TopBar stickybooleantrueSticks to the top of its scroll container.