Sidebar
Headless icon-rail collapsible sidebar primitive.
Features
Headless sidebar state
Icon-rail collapse
Controlled or uncontrolled
Trigger and rail toggles
Composable menu structure
shadcn-compatible data attributes
Installation
npm install @ariaui/sidebar
Examples
Sidebar is headless and icon-rail collapsible. Compose Sidebar.Root, Panel, Trigger, Rail, and menu parts, then style the rail from data-state and the sidebar width CSS variables.
Default
Default sidebar that collapses from full labels to compact icon buttons.
No preview output yet.
Framer Motion
Collapse the sidebar with Framer Motion — panel width and label fades stay in sync with open from Sidebar.useSidebar(), while menu buttons keep a fixed icon anchor so icons do not drift during the transition. Toggle the Home item to animate submenu open/close with height, opacity, and staggered item fades.
Sidebar collapse animated with Framer Motion on panel width and label fades, synced to Sidebar.useSidebar().
No preview output yet.
Anatomy
import * as Sidebar from "@ariaui/sidebar";
export default function Example() {
return (
<Sidebar.Root>
<Sidebar.Panel>
<Sidebar.Header />
<Sidebar.Content>
<Sidebar.Group>
<Sidebar.GroupLabel />
<Sidebar.GroupContent>
<Sidebar.Menu>
<Sidebar.MenuItem>
<Sidebar.MenuButton />
</Sidebar.MenuItem>
</Sidebar.Menu>
</Sidebar.GroupContent>
</Sidebar.Group>
</Sidebar.Content>
</Sidebar.Panel>
<Sidebar.Rail />
<Sidebar.Inset />
</Sidebar.Root>
);
}
API Reference
Root
State container for a headless icon-rail collapsible sidebar. Provides state and metadata to child parts.
| Prop | Type | Default |
|---|---|---|
open | boolean | — |
defaultOpen | boolean | true |
onOpenChange | (open: boolean) => void | — |
side | "left" | "right" | "left" |
collapsible | "icon" | "none" | "icon" |
keyboardShortcut | string | null | "b" |
| Attribute | Values |
|---|---|
| data-state | "expanded" | "collapsed" |
| data-side | "left" | "right" |
| data-collapsible | "icon" | "none" |
Parts
Panel
Sidebar panel host. Renders an aside by default and can slot props onto a custom host with asChild.
| Prop | Type | Default |
|---|---|---|
asChild | boolean | false |
| Attribute | Values |
|---|---|
| id | Generated panel id used by Trigger |
| data-sidebar | "sidebar" |
| data-state | "expanded" | "collapsed" |
Trigger
Button that toggles the sidebar expanded state.
| Prop | Type | Default |
|---|---|---|
asChild | boolean | false |
| Attribute | Values |
|---|---|
| aria-controls | ID of the Panel element |
| aria-expanded | "true" when expanded |
| data-sidebar | "trigger" |
| data-state | "expanded" | "collapsed" |
Rail
Thin hit target for toggling the sidebar from the panel edge.
| Attribute | Values |
|---|---|
| aria-label | "Toggle Sidebar" by default |
| tabIndex | -1 by default |
| data-sidebar | "rail" |
Header, Content, Footer, Group, Menu, SubMenu
Headless structural parts for composing sidebar sections, groups, menu items, badges, actions, and nested links.
| Attribute | Values |
|---|---|
| data-sidebar | Part-specific identifier |
Accessibility
Sidebar.Trigger exposes aria-expanded and aria-controls for the panel it toggles. Use clear visible labels or screen-reader-only labels for icon-only triggers and menu buttons.
The sidebar package does not assign landmark labels automatically. Add aria-label or aria-labelledby to Sidebar.Panel when the navigation region needs a name, and keep final menu item semantics appropriate for your app.
The default Ctrl+B / Meta+B shortcut can be disabled with keyboardShortcut={null} when it conflicts with application shortcuts.