Skip to content

Sidebar

<Sidebar> is the app-wide navigation rail — collapsible to icons or expanded with labels. Composed of SidebarProvider, Sidebar, SidebarHeader, SidebarContent, SidebarFooter, SidebarGroup, SidebarMenu / SidebarMenuItem / SidebarMenuButton, and the page-side SidebarInset + SidebarTrigger.

import from "@na/ui/components/sidebar" ▶ Open in Storybook packages/ui/src/components/sidebar.tsx

When to use

  • Every multi-page app needs one Sidebar at the root.
  • Navigate between top-level surfaces (Home, Agents, Members, Settings).

Don’t use Sidebar for: per-page navigation (Tabs), detail-page sub-navigation (DetailPageBar tabs), or in-section disclosure (Accordion).

Default

Agents
List…
<SidebarProvider>
<Sidebar collapsible="icon">
<SidebarHeader>
<div className="px-2 py-1.5 text-sm font-semibold">My App</div>
</SidebarHeader>
<SidebarContent>
<SidebarGroup>
<SidebarGroupLabel>Workspace</SidebarGroupLabel>
<SidebarMenu>
<SidebarMenuItem>
<SidebarMenuButton><IconHome />Home</SidebarMenuButton>
</SidebarMenuItem>
<SidebarMenuItem>
<SidebarMenuButton isActive><IconBolt />Agents</SidebarMenuButton>
</SidebarMenuItem>
</SidebarMenu>
</SidebarGroup>
</SidebarContent>
</Sidebar>
<SidebarInset>
<header><SidebarTrigger /></header>
<main></main>
</SidebarInset>
</SidebarProvider>

Anatomy

  • SidebarProvider — Wraps the app. Owns the open / collapsed state.
  • Sidebar — The rail itself. collapsible="icon" shrinks to icons; collapsible="offcanvas" slides off.
  • SidebarTrigger — Toggle button. Place it inside the page header (typically inside ListPageBar).
  • SidebarInset — The page-side area opposite the rail.
  • SidebarHeader / SidebarContent / SidebarFooter — Vertical sections.
  • SidebarGroup + SidebarGroupLabel — Section group with header.
  • SidebarMenu / SidebarMenuItem / SidebarMenuButton — Navigation items. isActive for the current route.
  • SidebarMenuSub / SidebarMenuSubItem / SidebarMenuSubButton — Nested items under a top-level menu.

Design guidelines

✓ Do

  • Use icons + labels. Icons alone fail the screen-reader contract; labels alone waste rail width.
  • Set isActive on the current route's SidebarMenuButton — the active state is the wayfinding signal.
  • Place SidebarTrigger at the top-left of every page (ListPageBar wires this for you).

✗ Don't

  • Nest 3+ levels of menu. Depth is a smell — flatten the IA or split into separate apps.
  • Render SidebarTrigger outside SidebarProvider — it relies on the context.
  • Style the rail with custom colors. Use the bg-sidebar / text-sidebar-foreground tokens.

Accessibility

  • The rail is a landmark <aside>.
  • Active item carries aria-current="page".
  • Trigger toggles via Radix Sheet for off-canvas mode; native CSS for icon mode.
  • Keyboard: Tab through items, arrow keys within menus.

▶ Open Sidebar stories in Storybook