Navigation and layout

Sidebar

A responsive application sidebar with rails, panels, menus, and collapsible modes.

⠋

Install

npx shadcn@latest add https://4af.selfsimilar.dev/r/sidebar.json

Usage

import {
  Sidebar,
  SidebarContent,
  SidebarMenu,
  SidebarMenuCollapsible,
  SidebarMenuCollapsibleContent,
  SidebarMenuCollapsibleTrigger,
  SidebarProvider,
  SidebarTrigger,
} from "@/components/ui/sidebar";

<SidebarProvider>
  <Sidebar>
    <SidebarContent>
      <SidebarMenu>
        <SidebarMenuCollapsible defaultOpen>
          <SidebarMenuCollapsibleTrigger>Projects</SidebarMenuCollapsibleTrigger>
          <SidebarMenuCollapsibleContent>Navigation</SidebarMenuCollapsibleContent>
        </SidebarMenuCollapsible>
      </SidebarMenu>
    </SidebarContent>
  </Sidebar>
  <main><SidebarTrigger />Page content</main>
</SidebarProvider>

API

Main exports: SidebarProvider, Sidebar, SidebarPanel, SidebarHeaderButton, and the menu, group, submenu, action, badge, and skeleton parts

A responsive application sidebar.

  • variant: sidebar, floating, inset, split, split-floating, or split-inset.
  • Controlled or uncontrolled collapse, menu sections, nested rows, collapsible menu rows, badges, and loading skeletons.
  • A full-width primary action in the header (SidebarHeaderButton).
  • Split layouts pair SidebarRailButton controls, each with a value, with SidebarPanel sections. activePanel, defaultActivePanel, and onActivePanelChange select the wide panel.

SidebarRailButton tooltip="Projects" labels a rail icon. Moving between rail icons opens their tooltips immediately, and the entrance transition still plays.

With collapsible="offcanvas", collapsed navigation leaves the tab order and accessibility tree once its exit finishes. If collapse happens while focus is inside, focus returns to the external SidebarTrigger in the same provider, or the edge SidebarRail when present. Keep a trigger outside the panel so keyboard users can reopen it. Icon and noncollapsing sidebars keep their navigation available.

SidebarMenuButton supports size="sm", size="default", and size="lg". The compact sm row uses a 6px radius; default and lg use an 8px radius. Nested SidebarMenuSubButton rows use a 6px radius, and fixed split-rail buttons are 32px squares with an 8px radius.

Collapsible menu sections

SidebarGroup provides visual grouping but does not own open state. For an expandable menu row, use SidebarMenuCollapsible with SidebarMenuCollapsibleTrigger and SidebarMenuCollapsibleContent:

<SidebarMenu>
  <SidebarMenuCollapsible defaultOpen>
    <SidebarMenuCollapsibleTrigger>
      <Folder />
      <span>Projects</span>
    </SidebarMenuCollapsibleTrigger>
    <SidebarMenuCollapsibleContent>
      <SidebarMenuSub>
        <SidebarMenuSubItem>
          <SidebarMenuSubButton href="/projects/acme">Acme</SidebarMenuSubButton>
        </SidebarMenuSubItem>
      </SidebarMenuSub>
    </SidebarMenuCollapsibleContent>
  </SidebarMenuCollapsible>
</SidebarMenu>

The trigger includes a trailing ChevronDown that points right while closed and down while open. Pass chevron={false} when the trigger supplies its own indicator. A sibling SidebarMenuAction sits just before the chevron, and a sibling SidebarMenuBadge takes its own slot before both, so they never overlap. Hovering a nested row highlights only that row. The collapsible root accepts Base UI's defaultOpen, open, onOpenChange, and disabled props.

Header composition

A header contains one full-width SidebarHeaderButton, or two wrapped in SidebarHeaderRow:

<SidebarHeader>
  <span>Emails</span>
  <SidebarHeaderRow>
    <SidebarHeaderButton><Plus />Compose</SidebarHeaderButton>
    <SidebarHeaderButton variant="outline"><Search />Search</SidebarHeaderButton>
  </SidebarHeaderRow>
</SidebarHeader>

The row owns spacing, divides width evenly, and stacks its buttons when the sidebar collapses to icons. Add className="flex-none" when a button should retain its own width. Compose menus with Dropdown Menu rather than embedding a separate menu implementation in Sidebar.

Pinning the panel open

hideCollapseHandle removes the edge strip that toggles the panel. Use it when the panel is pinned open (a controlled open that never changes), so there is no control that does nothing.

<Sidebar variant="split-inset" collapsible="icon" hideCollapseHandle={pinned} rail={rail}>