{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"sidebar","type":"registry:ui","title":"Sidebar","description":"A collapsible navigation rail for an app's main sections.","dependencies":["clsx","lucide-react","tailwind-merge"],"registryDependencies":["https://caliperui.site/r/styles.json"],"files":[{"path":"ui/lib/cn.ts","type":"registry:ui","target":"components/ui/lib/cn.ts","content":"import { clsx, type ClassValue } from \"clsx\";\nimport { extendTailwindMerge } from \"tailwind-merge\";\n\nconst twMerge = extendTailwindMerge({\n  extend: { theme: { radius: [\"control\", \"surface\", \"overlay\"], shadow: [\"overlay\"] } },\n});\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n"},{"path":"ui/sidebar.tsx","type":"registry:ui","target":"components/ui/sidebar.tsx","content":"\"use client\";\n\nimport { PanelLeft } from \"lucide-react\";\nimport { useState, type ReactNode } from \"react\";\nimport { cn } from \"./lib/cn\";\nimport \"./sidebar.css\";\n\nexport type SidebarItem = { id: string; label: string; icon: ReactNode };\n\nexport function Sidebar({\n  label = \"Project\",\n  items,\n  value,\n  defaultValue,\n  onValueChange,\n  collapsed,\n  defaultCollapsed = false,\n  onCollapsedChange,\n  className,\n}: {\n  label?: string;\n  items: readonly SidebarItem[];\n  value?: string;\n  defaultValue?: string;\n  onValueChange?: (value: string) => void;\n  collapsed?: boolean;\n  defaultCollapsed?: boolean;\n  onCollapsedChange?: (collapsed: boolean) => void;\n  className?: string;\n}) {\n  const [localValue, setLocalValue] = useState(defaultValue ?? items[0]?.id ?? \"\");\n  const [localCollapsed, setLocalCollapsed] = useState(defaultCollapsed);\n  const current = value ?? localValue;\n  const closed = collapsed ?? localCollapsed;\n\n  function select(next: string) {\n    if (value == null) setLocalValue(next);\n    onValueChange?.(next);\n  }\n\n  function toggle() {\n    const next = !closed;\n    if (collapsed == null) setLocalCollapsed(next);\n    onCollapsedChange?.(next);\n  }\n\n  return (\n    <aside data-slot=\"sidebar\" data-collapsed={closed || undefined} aria-label={label} className={cn(\"flex h-72 flex-col overflow-hidden border-r border-border bg-background\", className)}>\n      <div className=\"flex h-12 items-center gap-2 px-2\">\n        <button type=\"button\" aria-pressed={closed} aria-label={closed ? \"Expand sidebar\" : \"Collapse sidebar\"} className=\"grid size-9 shrink-0 place-items-center rounded-surface outline-none hover:bg-muted active:bg-[var(--raised-press)] focus-visible:outline-solid focus-visible:outline-2 focus-visible:outline-ring\" onClick={toggle}>\n          <PanelLeft aria-hidden=\"true\" className=\"size-4\" />\n        </button>\n        <span data-slot=\"sidebar-label\"><span className=\"truncate text-sm font-medium\">{label}</span></span>\n      </div>\n      <nav className=\"grid gap-1 px-2\">\n        {items.map((item) => (\n          <button\n            key={item.id}\n            type=\"button\"\n            aria-current={item.id === current ? \"page\" : undefined}\n            title={item.label}\n            className=\"flex h-9 items-center gap-2 rounded-surface px-2 text-sm outline-none hover:bg-muted active:bg-[var(--raised-press)] focus-visible:outline-solid focus-visible:outline-2 focus-visible:outline-ring aria-[current=page]:bg-selected\"\n            onClick={() => select(item.id)}\n          >\n            <span className=\"grid size-5 shrink-0 place-items-center\">{item.icon}</span>\n            <span data-slot=\"sidebar-label\"><span className=\"truncate\">{item.label}</span></span>\n          </button>\n        ))}\n      </nav>\n    </aside>\n  );\n}\n"},{"path":"ui/sidebar.css","type":"registry:file","target":"components/ui/sidebar.css","content":"/* sidebar.tsx's styles; it imports this file. Edit freely. */\n@layer theme, base, components, utilities;\n\n@layer components {\n  [data-slot=\"sidebar\"] {\n    width: 15rem;\n    transition: width var(--duration-travel) var(--ease-settle);\n  }\n  [data-slot=\"sidebar\"][data-collapsed] {\n    width: 4rem;\n  }\n  [data-slot=\"sidebar-label\"] {\n    display: grid;\n    grid-template-columns: 1fr;\n    min-width: 0;\n    overflow: hidden;\n    opacity: 1;\n    transition:\n      grid-template-columns var(--duration-travel) var(--ease-showcase),\n      opacity var(--duration-fast) var(--ease-out);\n  }\n  [data-slot=\"sidebar\"][data-collapsed] [data-slot=\"sidebar-label\"] {\n    grid-template-columns: 0fr;\n    opacity: 0;\n  }\n\n  @media (prefers-reduced-motion: reduce) {\n    [data-slot=\"sidebar\"] {\n      transition-duration: 400ms;\n    }\n  }\n  @media (prefers-reduced-motion: no-preference) {\n    [data-slot=\"sidebar\"] [aria-current=\"page\"] { animation: caliper-select-in var(--duration-normal) var(--ease-out) both; }\n  }\n}\n"}],"categories":["navigation"],"meta":{"tier":"free","license":"MIT","family":"sidebar","docs":"/docs/components/sidebar"}}