Sidebar
Collapsible app sidebar with icon rail, mobile sheet, Ctrl/Cmd+B shortcut, and persisted state.
pnpm dlx @glinui/cli@latest add sidebarInstallation
pnpm dlx @glinui/cli@latest add sidebarPrefer the package?
Usage
The sidebar animates its width when it collapses. Width is a documented exception to the transform and opacity only motion rule, because the content column must reflow with it. The transition is disabled under prefers-reduced-motion.
Use containerClassName to control the docking element, for example static h-full when the sidebar lives inside a bounded frame instead of the viewport.
Variants
Every look of the shared vocabulary. glinr (the default) is a lifted rail with hairline separators and a raised pill for the active item; plain is flat and shadcn-like. Collapsed icon mode keeps the same pill as a circle.
import { Sidebar, SidebarContent, SidebarGroup, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarMenu, SidebarMenuButton, SidebarMenuItem, SidebarProvider } from "@glinui/ui"
const variants = ["glinr", "plain", "solid", "soft", "outline", "ghost", "gradient", "glass"] as const
export function Demo() { return variants.map((variant) => ( <SidebarProvider key={variant}> <Sidebar variant={variant} collapsible="none"> <SidebarHeader>{variant}</SidebarHeader> <SidebarContent> <SidebarGroup> <SidebarGroupLabel>Platform</SidebarGroupLabel> <SidebarGroupContent> <SidebarMenu> <SidebarMenuItem><SidebarMenuButton isActive>Home</SidebarMenuButton></SidebarMenuItem> <SidebarMenuItem><SidebarMenuButton>Inbox</SidebarMenuButton></SidebarMenuItem> </SidebarMenu> </SidebarGroupContent> </SidebarGroup> </SidebarContent> </Sidebar> </SidebarProvider> ))}Glass (opt-in)
Glass is opt-in and needs a colourful or photographic backdrop behind the rail. The frame supplies one here.
import { Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarInset, SidebarMenu, SidebarMenuButton, SidebarMenuItem, SidebarProvider, SidebarRail, SidebarTrigger} from "@glinui/ui"import { House, Gear } from "@phosphor-icons/react"
export function Layout({ children }: { children: React.ReactNode }) { return ( <SidebarProvider> <Sidebar variant="glass" collapsible="icon"> <SidebarHeader>Glin Studio</SidebarHeader> <SidebarContent> <SidebarGroup> <SidebarGroupLabel>Platform</SidebarGroupLabel> <SidebarGroupContent> <SidebarMenu> <SidebarMenuItem> <SidebarMenuButton isActive tooltip="Home"><House /><span>Home</span></SidebarMenuButton> </SidebarMenuItem> <SidebarMenuItem> <SidebarMenuButton tooltip="Settings"><Gear /><span>Settings</span></SidebarMenuButton> </SidebarMenuItem> </SidebarMenu> </SidebarGroupContent> </SidebarGroup> </SidebarContent> <SidebarFooter>Footer</SidebarFooter> <SidebarRail /> </Sidebar> <SidebarInset> <SidebarTrigger /> {children} </SidebarInset> </SidebarProvider> )}Off-canvas
Collapses fully; reopen with the trigger.
import { Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarInset, SidebarMenu, SidebarMenuButton, SidebarMenuItem, SidebarProvider, SidebarRail, SidebarTrigger} from "@glinui/ui"import { House, Gear } from "@phosphor-icons/react"
export function Layout({ children }: { children: React.ReactNode }) { return ( <SidebarProvider> <Sidebar collapsible="offcanvas"> <SidebarHeader>Glin Studio</SidebarHeader> <SidebarContent> <SidebarGroup> <SidebarGroupLabel>Platform</SidebarGroupLabel> <SidebarGroupContent> <SidebarMenu> <SidebarMenuItem> <SidebarMenuButton isActive tooltip="Home"><House /><span>Home</span></SidebarMenuButton> </SidebarMenuItem> <SidebarMenuItem> <SidebarMenuButton tooltip="Settings"><Gear /><span>Settings</span></SidebarMenuButton> </SidebarMenuItem> </SidebarMenu> </SidebarGroupContent> </SidebarGroup> </SidebarContent> <SidebarFooter>Footer</SidebarFooter> <SidebarRail /> </Sidebar> <SidebarInset> <SidebarTrigger /> {children} </SidebarInset> </SidebarProvider> )}Accessibility
- The panel is a `nav` landmark with an accessible name.
- The current page uses `aria-current="page"`; collapsible group labels expose `aria-expanded` and `aria-controls`.
- On small screens the sidebar becomes a Sheet dialog with focus trap and Escape to close.
- In icon mode, labels stay in the accessibility tree (visually hidden) and tooltips reveal them.
Keyboard Interactions
| Key | Action |
|---|---|
| Ctrl/Cmd + B | Toggle the sidebar. |
| Tab / Shift + Tab | Move through menu buttons. |
| Enter / Space | Activate a button or toggle a group. |
| Escape | Close the mobile sheet. |
ARIA Attributes
- `<nav aria-label>`
- `aria-current="page"` on the active button
- `aria-expanded` on trigger and collapsible group labels
Reduced Motion
Width and caret transitions are disabled; state changes apply instantly.
Affected properties
widthtransform (rotate)API Reference
SidebarProvider
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
defaultOpen | boolean | No | true | Initial open state when uncontrolled. |
open / onOpenChange | boolean / (open: boolean) => void | - | - | Controlled open state. |
storageKey | string | null | - | "glin-sidebar-state" | localStorage key for persisting desktop state. Null disables persistence. |
collapsible | boolean | No | false | Let users collapse this group by activating its label. |
Sidebar
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
side | "start" | "end" | - | start | Inline edge to dock to. Flips in RTL. |
variant | "glinr" | "plain" | "solid" | "soft" | "outline" | "ghost" | "gradient" | "glass" | - | ambient style (glinr) | Surface look. Omit it for the ambient design style: a lifted rail with hairline separators and a raised pill for the active item. `plain` is flat, `glass` is opt-in and needs a backdrop. Legacy `default` follows the ambient style. |
collapsible | boolean | No | offcanvas | Collapse to nothing, to an icon rail, or never. |
label | string | - | Sidebar | Accessible name of the navigation landmark. |
containerClassName | string | - | - | Classes for the docking element, e.g. `static h-full` inside a bounded frame. |
defaultOpen | boolean | No | true | Initial open state for a collapsible group. |
SidebarMenuButton
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
isActive | boolean | - | false | Marks the current page and sets aria-current. |
tooltip | string | - | - | Label shown on hover when collapsed to icons. |
asChild | boolean | - | false | Render a link element. |
variant / size | "default" | "outline" / "sm" | "md" | "lg" | - | - | Button style and height. |
collapsible | boolean | No | false | Let users collapse this group by activating its label. |
defaultOpen | boolean | No | true | Initial open state for a collapsible group. |
SidebarGroup
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
collapsible | boolean | No | false | Makes the label a toggle with aria-expanded. |
defaultOpen | boolean | No | true | Initial open state of a collapsible group. |
Other parts
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
useSidebar() | { state, open, setOpen, openMobile, setOpenMobile, isMobile, toggleSidebar } | - | - | Read and control the sidebar from any child. |
collapsible | boolean | No | false | Let users collapse this group by activating its label. |
defaultOpen | boolean | No | true | Initial open state for a collapsible group. |
Source
Import directly from the package or browse the source on GitHub. Click any file to view it.
Import
import { Sidebar } from "@glinui/ui"Dependencies
@glinui/ui@phosphor-icons/react@radix-ui/react-slotclass-variance-authorityGenerated API Snapshot
Beta
Generated API Snapshot
BetaAuto-extracted from TypeScript source in packages/ui/src/components/sidebar.tsx. This section is in beta and may lag behind hand-curated docs. Regenerate with pnpm --filter @glinui/docs api:generate.
Generated: 2026-10-08T01:41:21.546Z · Full index: /docs/api-metadata
Primary Props Type
SidebarProps
SidebarGroupProps
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
collapsible | boolean | No | false | Let users collapse this group by activating its label. |
defaultOpen | boolean | No | true | Initial open state for a collapsible group. |
SidebarMenuButtonProps
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
asChild | boolean | No | false | - |
isActive | boolean | No | false | Marks the current page. Sets aria-current="page". |
size | "sm" | "md" | "lg" | No | "md" | Variant option from menuButtonVariants. |
tooltip | string | No | - | Tooltip shown only while the sidebar is collapsed to icons. |
variant | "default" | "outline" | No | "default" | Variant option from menuButtonVariants. |
SidebarProps
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
collapsible | "offcanvas" | "icon" | "none" | No | false | How the sidebar collapses on desktop. |
containerClassName | string | No | - | Class names for the outer docking element (height, position). Defaults to sticky full viewport height. |
label | string | No | "Sidebar" | Accessible name for the navigation landmark. |
side | "start" | "end" | No | "start" | Which inline edge the sidebar docks to. |
variant | PanelVariantProp | No | - | Surface look. Omit for the ambient design style (glinr by default): a lifted rail with hairline separators and a raised pill for the active item. `glass` is opt-in and needs a rich backdrop. |