{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "radix-sidebar", "type": "registry:ui", "title": "Radix Sidebar", "description": "A composable, themeable and customizable sidebar component. Created by Shadcn and animated by Animate UI.", "dependencies": [ "radix-ui", "class-variance-authority", "lucide-react", "motion" ], "registryDependencies": [ "https://animate-ui.com/r/radix-sheet", "https://animate-ui.com/r/radix-tooltip", "https://animate-ui.com/r/motion-highlight", "use-mobile", "button", "input", "label", "separator", "skeleton" ], "files": [ { "path": "registry/radix/sidebar/index.tsx", "content": "'use client';\n\nimport * as React from 'react';\nimport { Slot } from 'radix-ui';\nimport { VariantProps, cva } from 'class-variance-authority';\nimport { PanelLeftIcon } from 'lucide-react';\nimport { type Transition } from 'motion/react';\n\nimport { cn } from '@/lib/utils';\nimport { useIsMobile } from '@/hooks/use-mobile';\nimport { Button } from '@/components/ui/button';\nimport { Input } from '@/components/ui/input';\nimport { Separator } from '@/components/ui/separator';\nimport { Skeleton } from '@/components/ui/skeleton';\nimport {\n Sheet,\n SheetContent,\n SheetDescription,\n SheetHeader,\n SheetTitle,\n} from '@/components/animate-ui/radix/sheet';\nimport {\n Tooltip,\n TooltipContent,\n TooltipProvider,\n TooltipTrigger,\n} from '@/components/animate-ui/radix/tooltip';\nimport {\n MotionHighlight,\n MotionHighlightItem,\n} from '@/components/animate-ui/effects/motion-highlight';\n\nconst SIDEBAR_COOKIE_NAME = 'sidebar_state';\nconst SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7;\nconst SIDEBAR_WIDTH = '16rem';\nconst SIDEBAR_WIDTH_MOBILE = '18rem';\nconst SIDEBAR_WIDTH_ICON = '3rem';\nconst SIDEBAR_KEYBOARD_SHORTCUT = 'b';\n\ntype SidebarContextProps = {\n state: 'expanded' | 'collapsed';\n open: boolean;\n setOpen: (open: boolean) => void;\n openMobile: boolean;\n setOpenMobile: (open: boolean) => void;\n isMobile: boolean;\n toggleSidebar: () => void;\n};\n\nconst SidebarContext = React.createContext(null);\n\nfunction useSidebar() {\n const context = React.useContext(SidebarContext);\n if (!context) {\n throw new Error('useSidebar must be used within a SidebarProvider.');\n }\n\n return context;\n}\n\ntype SidebarProviderProps = React.ComponentProps<'div'> & {\n defaultOpen?: boolean;\n open?: boolean;\n onOpenChange?: (open: boolean) => void;\n};\n\nfunction SidebarProvider({\n defaultOpen = true,\n open: openProp,\n onOpenChange: setOpenProp,\n className,\n style,\n children,\n ...props\n}: SidebarProviderProps) {\n const isMobile = useIsMobile();\n const [openMobile, setOpenMobile] = React.useState(false);\n\n // This is the internal state of the sidebar.\n // We use openProp and setOpenProp for control from outside the component.\n const [_open, _setOpen] = React.useState(defaultOpen);\n const open = openProp ?? _open;\n const setOpen = React.useCallback(\n (value: boolean | ((value: boolean) => boolean)) => {\n const openState = typeof value === 'function' ? value(open) : value;\n if (setOpenProp) {\n setOpenProp(openState);\n } else {\n _setOpen(openState);\n }\n\n // This sets the cookie to keep the sidebar state.\n document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`;\n },\n [setOpenProp, open],\n );\n\n // Helper to toggle the sidebar.\n const toggleSidebar = React.useCallback(() => {\n return isMobile ? setOpenMobile((open) => !open) : setOpen((open) => !open);\n }, [isMobile, setOpen, setOpenMobile]);\n\n // Adds a keyboard shortcut to toggle the sidebar.\n React.useEffect(() => {\n const handleKeyDown = (event: KeyboardEvent) => {\n if (\n event.key === SIDEBAR_KEYBOARD_SHORTCUT &&\n (event.metaKey || event.ctrlKey)\n ) {\n event.preventDefault();\n toggleSidebar();\n }\n };\n\n window.addEventListener('keydown', handleKeyDown);\n return () => window.removeEventListener('keydown', handleKeyDown);\n }, [toggleSidebar]);\n\n // We add a state so that we can do data-state=\"expanded\" or \"collapsed\".\n // This makes it easier to style the sidebar with Tailwind classes.\n const state = open ? 'expanded' : 'collapsed';\n\n const contextValue = React.useMemo(\n () => ({\n state,\n open,\n setOpen,\n isMobile,\n openMobile,\n setOpenMobile,\n toggleSidebar,\n }),\n [state, open, setOpen, isMobile, openMobile, setOpenMobile, toggleSidebar],\n );\n\n return (\n \n \n \n {children}\n \n \n \n );\n}\n\ntype SidebarProps = React.ComponentProps<'div'> & {\n side?: 'left' | 'right';\n variant?: 'sidebar' | 'floating' | 'inset';\n collapsible?: 'offcanvas' | 'icon' | 'none';\n containerClassName?: string;\n animateOnHover?: boolean;\n transition?: Transition;\n};\n\nfunction Sidebar({\n side = 'left',\n variant = 'sidebar',\n collapsible = 'offcanvas',\n className,\n children,\n animateOnHover = true,\n containerClassName,\n transition = { type: 'spring', stiffness: 350, damping: 35 },\n ...props\n}: SidebarProps) {\n const { isMobile, state, openMobile, setOpenMobile } = useSidebar();\n\n if (collapsible === 'none') {\n return (\n \n \n {children}\n \n \n );\n }\n\n if (isMobile) {\n return (\n \n button]:hidden\"\n style={\n {\n '--sidebar-width': SIDEBAR_WIDTH_MOBILE,\n } as React.CSSProperties\n }\n side={side}\n >\n \n Sidebar\n Displays the mobile sidebar.\n \n \n
{children}
\n \n \n
\n );\n }\n\n return (\n