Installation

pnpm dlx shadcn@latest add @cortexcn/sidebarThe sidebar reads its colors from the --sidebar tokens that shadcn init adds to your theme.
Usage
import { Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupAction, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarInput, SidebarInset, SidebarMenu, SidebarMenuAction, SidebarMenuBadge, SidebarMenuButton, SidebarMenuItem, SidebarMenuSkeleton, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarProvider, SidebarRail, SidebarSeparator, SidebarTrigger, useSidebar } from "@/components/sidebar";Wrap your layout in SidebarProvider, put a Sidebar next to a SidebarInset, and add a SidebarTrigger to toggle it. Press Ctrl+B (Cmd+B on a Mac) to toggle it from the keyboard.
Examples
Default
"use client"import * as React from "react"import { DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuTrigger } from "@/components/dropdown-menu"import { Item, ItemActions, ItemContent, ItemDescription, ItemTitle } from "@/components/item"import { Label } from "@/components/label"import { Sidebar, SidebarContent, SidebarGroup, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarInput, SidebarInset, SidebarMenu, SidebarMenuButton, SidebarMenuItem, SidebarProvider, SidebarRail, SidebarTrigger } from "@/components/sidebar"import { CheckIcon, ChevronsUpDownIcon, SearchIcon } from "lucide-react"export function SidebarDefaultExample() { const data = { versions: ["1.0.1", "1.1.0-alpha", "2.0.0-beta1"], navMain: [ { title: "Getting Started", url: "#", items: [ { title: "Installation", url: "#", }, { title: "Project Structure", url: "#", }, ], }, { title: "Build Your Application", url: "#", items: [ { title: "Routing", url: "#", }, { title: "Data Fetching", url: "#", isActive: true, }, { title: "Rendering", url: "#", }, { title: "Caching", url: "#", }, { title: "Styling", url: "#", }, { title: "Optimizing", url: "#", }, { title: "Configuring", url: "#", }, { title: "Testing", url: "#", }, { title: "Authentication", url: "#", }, { title: "Deploying", url: "#", }, { title: "Upgrading", url: "#", }, { title: "Examples", url: "#", }, ], }, { title: "API Reference", url: "#", items: [ { title: "Components", url: "#", }, { title: "File Conventions", url: "#", }, { title: "Functions", url: "#", }, { title: "next.config.js Options", url: "#", }, { title: "CLI", url: "#", }, { title: "Edge Runtime", url: "#", }, ], }, { title: "Architecture", url: "#", items: [ { title: "Accessibility", url: "#", }, { title: "Fast Refresh", url: "#", }, { title: "Next.js Compiler", url: "#", }, { title: "Supported Browsers", url: "#", }, { title: "Turbopack", url: "#", }, ], }, ], } const [selectedVersion, setSelectedVersion] = React.useState(data.versions[0]) return ( <SidebarProvider> <Sidebar> <SidebarHeader> <SidebarMenu> <SidebarMenuItem> <DropdownMenu> <DropdownMenuTrigger asChild> <SidebarMenuButton size="lg" className="data-open:bg-sidebar-accent data-open:text-sidebar-accent-foreground" > <Item className="p-0" size="xs"> <ItemContent> <ItemTitle className="text-sm">Documentation</ItemTitle> <ItemDescription>v{selectedVersion}</ItemDescription> </ItemContent> <ItemActions> <ChevronsUpDownIcon /> </ItemActions> </Item> </SidebarMenuButton> </DropdownMenuTrigger> <DropdownMenuContent> <DropdownMenuGroup> {data.versions.map((version) => ( <DropdownMenuItem key={version} onSelect={() => setSelectedVersion(version)} > v{version}{" "} {version === selectedVersion && ( <CheckIcon className="ml-auto" /> )} </DropdownMenuItem> ))} </DropdownMenuGroup> </DropdownMenuContent> </DropdownMenu> </SidebarMenuItem> </SidebarMenu> <form> <SidebarGroup className="py-0"> <SidebarGroupContent className="relative"> <Label htmlFor="search" className="sr-only"> Search </Label> <SidebarInput id="search" placeholder="Search the docs..." className="pl-8" /> <SearchIcon className="pointer-events-none absolute top-1/2 left-2 size-4 -translate-y-1/2 opacity-50 select-none" /> </SidebarGroupContent> </SidebarGroup> </form> </SidebarHeader> <SidebarContent> {data.navMain.map((item) => ( <SidebarGroup key={item.title}> <SidebarGroupLabel>{item.title}</SidebarGroupLabel> <SidebarGroupContent> <SidebarMenu> {item.items.map((subItem) => ( <SidebarMenuItem key={subItem.title}> <SidebarMenuButton asChild isActive={subItem.isActive}> <a href={subItem.url}>{subItem.title}</a> </SidebarMenuButton> </SidebarMenuItem> ))} </SidebarMenu> </SidebarGroupContent> </SidebarGroup> ))} </SidebarContent> <SidebarRail /> </Sidebar> <SidebarInset> <header className="flex h-16 shrink-0 items-center gap-2 border-b px-4"> <SidebarTrigger className="-ml-1" /> </header> <div className="flex flex-1 flex-col gap-4 p-4"> <div className="grid auto-rows-min gap-4 md:grid-cols-3"> <div className="aspect-video rounded-xl bg-muted/50" /> <div className="aspect-video rounded-xl bg-muted/50" /> <div className="aspect-video rounded-xl bg-muted/50" /> </div> <div className="min-h-[100vh] flex-1 rounded-xl bg-muted/50 md:min-h-min" /> </div> </SidebarInset> </SidebarProvider> )}Floating
"use client"import { Button } from "@/components/button"import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/card"import { DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuTrigger } from "@/components/dropdown-menu"import { Field } from "@/components/field"import { Item, ItemContent, ItemDescription, ItemTitle } from "@/components/item"import { Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarHeader, SidebarInput, SidebarInset, SidebarMenu, SidebarMenuButton, SidebarMenuItem, SidebarProvider, SidebarRail, SidebarTrigger } from "@/components/sidebar"import { MoreHorizontalIcon } from "lucide-react"export function SidebarFloatingExample() { const data = { navMain: [ { title: "Getting Started", url: "#", items: [ { title: "Installation", url: "#", }, { title: "Project Structure", url: "#", }, ], }, { title: "Build Your Application", url: "#", items: [ { title: "Routing", url: "#", }, { title: "Data Fetching", url: "#", isActive: true, }, { title: "Rendering", url: "#", }, { title: "Caching", url: "#", }, { title: "Styling", url: "#", }, { title: "Optimizing", url: "#", }, { title: "Configuring", url: "#", }, { title: "Testing", url: "#", }, { title: "Authentication", url: "#", }, { title: "Deploying", url: "#", }, { title: "Upgrading", url: "#", }, { title: "Examples", url: "#", }, ], }, { title: "API Reference", url: "#", items: [ { title: "Components", url: "#", }, { title: "File Conventions", url: "#", }, { title: "Functions", url: "#", }, { title: "next.config.js Options", url: "#", }, { title: "CLI", url: "#", }, { title: "Edge Runtime", url: "#", }, ], }, { title: "Architecture", url: "#", items: [ { title: "Accessibility", url: "#", }, { title: "Fast Refresh", url: "#", }, { title: "Next.js Compiler", url: "#", }, { title: "Supported Browsers", url: "#", }, { title: "Turbopack", url: "#", }, ], }, ], } return ( <SidebarProvider className="bg-background"> <Sidebar variant="floating"> <SidebarHeader> <SidebarMenu> <SidebarMenuItem> <SidebarMenuButton size="lg" asChild> <a href="#"> <Item className="p-0" size="xs"> <ItemContent> <ItemTitle className="text-sm">Documentation</ItemTitle> <ItemDescription>v1.0.0</ItemDescription> </ItemContent> </Item> </a> </SidebarMenuButton> </SidebarMenuItem> </SidebarMenu> </SidebarHeader> <SidebarContent> <SidebarGroup> <SidebarMenu> {data.navMain.map((item) => ( <DropdownMenu key={item.title}> <SidebarMenuItem> <DropdownMenuTrigger asChild> <SidebarMenuButton className="data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground"> {item.title}{" "} <MoreHorizontalIcon className="ml-auto" /> </SidebarMenuButton> </DropdownMenuTrigger> {item.items?.length ? ( <DropdownMenuContent side="right" align="start"> <DropdownMenuGroup> {item.items.map((subItem) => ( <DropdownMenuItem asChild key={subItem.title}> <a href={subItem.url}>{subItem.title}</a> </DropdownMenuItem> ))} </DropdownMenuGroup> </DropdownMenuContent> ) : null} </SidebarMenuItem> </DropdownMenu> ))} </SidebarMenu> </SidebarGroup> </SidebarContent> <SidebarFooter> <SidebarGroup className="pb-1"> <Card size="sm" className="-mx-1"> <CardHeader> <CardTitle className="text-sm"> Subscribe to our newsletter </CardTitle> <CardDescription> Opt-in to receive updates and news about the sidebar. </CardDescription> </CardHeader> <CardContent> <form> <Field> <SidebarInput type="email" placeholder="Email" /> <Button className="w-full bg-sidebar-primary text-sidebar-primary-foreground" size="sm" > Subscribe </Button> </Field> </form> </CardContent> </Card> </SidebarGroup> </SidebarFooter> <SidebarRail /> </Sidebar> <SidebarInset> <header className="flex h-16 shrink-0 items-center gap-2 px-4"> <SidebarTrigger className="-ml-1" /> </header> <div className="flex flex-1 flex-col gap-4 p-4 pt-0"> <div className="grid auto-rows-min gap-4 md:grid-cols-3"> <div className="aspect-video rounded-xl bg-muted/50" /> <div className="aspect-video rounded-xl bg-muted/50" /> <div className="aspect-video rounded-xl bg-muted/50" /> </div> <div className="min-h-screen flex-1 rounded-xl bg-muted/50 md:min-h-min" /> </div> </SidebarInset> </SidebarProvider> )}Collapsible to icons
"use client"import * as React from "react"import { Avatar, AvatarFallback, AvatarImage } from "@/components/avatar"import { Button } from "@/components/button"import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/collapsible"import { DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger } from "@/components/dropdown-menu"import { Item, ItemContent, ItemDescription, ItemMedia, ItemTitle } from "@/components/item"import { Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupLabel, SidebarHeader, SidebarInset, SidebarMenu, SidebarMenuButton, SidebarMenuItem, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarProvider, SidebarRail, SidebarTrigger } from "@/components/sidebar"import { BookOpen, BotIcon, ChevronRightIcon, ChevronsUpDownIcon, FrameIcon, MapIcon, PieChartIcon, Settings2Icon, TerminalSquareIcon } from "lucide-react"export function SidebarIconExample() { const data = { user: { name: "shadcn", email: "m@example.com", avatar: "/avatars/shadcn.jpg", }, teams: [ { name: "Acme Inc", plan: "Enterprise", }, { name: "Acme Corp.", plan: "Startup", }, { name: "Evil Corp.", plan: "Free", }, ], navMain: [ { title: "Playground", url: "#", icon: ( <TerminalSquareIcon /> ), isActive: true, items: [ { title: "History", url: "#", }, { title: "Starred", url: "#", }, { title: "Settings", url: "#", }, ], }, { title: "Models", url: "#", icon: ( <BotIcon /> ), items: [ { title: "Genesis", url: "#", }, { title: "Explorer", url: "#", }, { title: "Quantum", url: "#", }, ], }, { title: "Documentation", url: "#", icon: ( <BookOpen /> ), items: [ { title: "Introduction", url: "#", }, { title: "Get Started", url: "#", }, { title: "Tutorials", url: "#", }, { title: "Changelog", url: "#", }, ], }, { title: "Settings", url: "#", icon: ( <Settings2Icon /> ), items: [ { title: "General", url: "#", }, { title: "Team", url: "#", }, { title: "Billing", url: "#", }, { title: "Limits", url: "#", }, ], }, ], projects: [ { name: "Design Engineering", url: "#", icon: ( <FrameIcon /> ), }, { name: "Sales & Marketing", url: "#", icon: ( <PieChartIcon /> ), }, { name: "Travel", url: "#", icon: ( <MapIcon /> ), }, ], } const [activeTeam, setActiveTeam] = React.useState(data.teams[0]) return ( <SidebarProvider> <Sidebar collapsible="icon"> <SidebarHeader> <SidebarMenu> <SidebarMenuItem> <DropdownMenu> <DropdownMenuTrigger asChild> <SidebarMenuButton size="lg" className="data-open:bg-sidebar-accent data-open:text-sidebar-accent-foreground" > <Button size="icon-sm" asChild className="size-8"> <span> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" > <rect width="256" height="256" fill="none"></rect> <line x1="208" y1="128" x2="128" y2="208" fill="none" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="32" ></line> <line x1="192" y1="40" x2="40" y2="192" fill="none" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="32" ></line> </svg> </span> </Button> <div className="grid flex-1 text-left text-sm leading-tight"> <span className="truncate font-medium"> {activeTeam.name} </span> <span className="truncate text-xs"> {activeTeam.plan} </span> </div> <ChevronsUpDownIcon /> </SidebarMenuButton> </DropdownMenuTrigger> <DropdownMenuContent> <DropdownMenuGroup> <DropdownMenuLabel>Teams</DropdownMenuLabel> {data.teams.map((team) => ( <DropdownMenuItem key={team.name} onClick={() => setActiveTeam(team)} > {team.name} </DropdownMenuItem> ))} </DropdownMenuGroup> </DropdownMenuContent> </DropdownMenu> </SidebarMenuItem> </SidebarMenu> </SidebarHeader> <SidebarContent> <SidebarGroup> <SidebarGroupLabel>Platform</SidebarGroupLabel> <SidebarMenu> {data.navMain.map((item) => ( <Collapsible key={item.title} asChild defaultOpen={item.isActive} className="group/collapsible" > <SidebarMenuItem> <SidebarMenuButton tooltip={item.title} asChild> <CollapsibleTrigger> {item.icon} <span>{item.title}</span> <ChevronRightIcon className="ml-auto transition-transform duration-100 group-data-open/collapsible:rotate-90" /> </CollapsibleTrigger> </SidebarMenuButton> <CollapsibleContent> <SidebarMenuSub> {item.items?.map((subItem) => ( <SidebarMenuSubItem key={subItem.title}> <SidebarMenuSubButton asChild> <a href={subItem.url}>{subItem.title}</a> </SidebarMenuSubButton> </SidebarMenuSubItem> ))} </SidebarMenuSub> </CollapsibleContent> </SidebarMenuItem> </Collapsible> ))} </SidebarMenu> </SidebarGroup> <SidebarGroup className="group-data-[collapsible=icon]:hidden"> <SidebarGroupLabel>Projects</SidebarGroupLabel> <SidebarMenu> {data.projects.map((item) => ( <SidebarMenuItem key={item.name}> <SidebarMenuButton asChild> <a href={item.url}> {item.icon} {item.name} </a> </SidebarMenuButton> </SidebarMenuItem> ))} </SidebarMenu> </SidebarGroup> </SidebarContent> <SidebarFooter> <SidebarMenu> <SidebarMenuItem> <DropdownMenu> <DropdownMenuTrigger asChild> <SidebarMenuButton size="lg" className="data-open:bg-sidebar-accent data-open:text-sidebar-accent-foreground" > <Avatar> <AvatarImage src={data.user.avatar} alt={data.user.name} /> <AvatarFallback className="rounded-lg">CN</AvatarFallback> </Avatar> <div className="grid flex-1 text-left text-sm leading-tight"> <span className="truncate font-medium"> {data.user.name} </span> <span className="truncate text-xs"> {data.user.email} </span> </div> <ChevronsUpDownIcon /> </SidebarMenuButton> </DropdownMenuTrigger> <DropdownMenuContent> <DropdownMenuGroup> <DropdownMenuLabel> <Item size="xs"> <ItemMedia> <Avatar> <AvatarImage src={data.user.avatar} alt={data.user.name} /> <AvatarFallback>CN</AvatarFallback> </Avatar> </ItemMedia> <ItemContent> <ItemTitle>{data.user.name}</ItemTitle> <ItemDescription> {data.user.email}</ItemDescription> </ItemContent> </Item> </DropdownMenuLabel> </DropdownMenuGroup> <DropdownMenuSeparator /> <DropdownMenuGroup> <DropdownMenuItem>Account</DropdownMenuItem> <DropdownMenuItem>Billing</DropdownMenuItem> <DropdownMenuItem>Settings</DropdownMenuItem> </DropdownMenuGroup> <DropdownMenuSeparator /> <DropdownMenuGroup> <DropdownMenuItem>Log out</DropdownMenuItem> </DropdownMenuGroup> </DropdownMenuContent> </DropdownMenu> </SidebarMenuItem> </SidebarMenu> </SidebarFooter> <SidebarRail /> </Sidebar> <SidebarInset> <header className="flex h-16 shrink-0 items-center gap-2 border-b transition-[width,height] ease-linear group-has-data-[collapsible=icon]/sidebar-wrapper:h-12"> <div className="flex items-center gap-2 px-4"> <SidebarTrigger className="-ml-1" /> </div> </header> <div className="flex flex-1 flex-col gap-4 p-4"> <div className="grid auto-rows-min gap-4 md:grid-cols-3"> <div className="aspect-video rounded-xl bg-muted/50" /> <div className="aspect-video rounded-xl bg-muted/50" /> <div className="aspect-video rounded-xl bg-muted/50" /> </div> <div className="min-h-[100vh] flex-1 rounded-xl bg-muted/50 md:min-h-min" /> </div> </SidebarInset> </SidebarProvider> )}Inset
"use client"import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/collapsible"import { Sidebar, SidebarContent, SidebarGroup, SidebarGroupContent, SidebarGroupLabel, SidebarInset, SidebarMenu, SidebarMenuAction, SidebarMenuButton, SidebarMenuItem, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarProvider, SidebarRail, SidebarTrigger } from "@/components/sidebar"import { ChartLineIcon, ChevronRightIcon, FileIcon, HomeIcon, LifeBuoy, Send, Settings2Icon, ShoppingBagIcon, ShoppingCartIcon, UserIcon } from "lucide-react"export function SidebarInsetExample() { const data = { navMain: [ { title: "Dashboard", url: "#", icon: ( <HomeIcon /> ), isActive: true, items: [ { title: "Overview", url: "#", }, { title: "Analytics", url: "#", }, ], }, { title: "Analytics", url: "#", icon: ( <ChartLineIcon /> ), items: [ { title: "Reports", url: "#", }, { title: "Metrics", url: "#", }, ], }, { title: "Orders", url: "#", icon: ( <ShoppingBagIcon /> ), items: [ { title: "All Orders", url: "#", }, { title: "Pending", url: "#", }, { title: "Completed", url: "#", }, ], }, { title: "Products", url: "#", icon: ( <ShoppingCartIcon /> ), items: [ { title: "All Products", url: "#", }, { title: "Categories", url: "#", }, ], }, { title: "Invoices", url: "#", icon: ( <FileIcon /> ), }, { title: "Customers", url: "#", icon: ( <UserIcon /> ), }, { title: "Settings", url: "#", icon: ( <Settings2Icon /> ), }, ], navSecondary: [ { title: "Support", url: "#", icon: ( <LifeBuoy /> ), }, { title: "Feedback", url: "#", icon: ( <Send /> ), }, ], } return ( <SidebarProvider> <Sidebar variant="inset"> <SidebarContent> <SidebarGroup> <SidebarGroupLabel>Dashboard</SidebarGroupLabel> <SidebarMenu> {data.navMain.map((item) => ( <Collapsible key={item.title} asChild defaultOpen={item.isActive} > <SidebarMenuItem> <SidebarMenuButton asChild tooltip={item.title} isActive={item.isActive} > <a href={item.url}> {item.icon} <span>{item.title}</span> </a> </SidebarMenuButton> {item.items?.length ? ( <> <CollapsibleTrigger asChild> <SidebarMenuAction className="data-[state=open]:rotate-90"> <ChevronRightIcon /> <span className="sr-only">Toggle</span> </SidebarMenuAction> </CollapsibleTrigger> <CollapsibleContent> <SidebarMenuSub> {item.items.map((subItem) => ( <SidebarMenuSubItem key={subItem.title}> <SidebarMenuSubButton asChild> <a href={subItem.url}> <span>{subItem.title}</span> </a> </SidebarMenuSubButton> </SidebarMenuSubItem> ))} </SidebarMenuSub> </CollapsibleContent> </> ) : null} </SidebarMenuItem> </Collapsible> ))} </SidebarMenu> </SidebarGroup> <SidebarGroup className="mt-auto"> <SidebarGroupContent> <SidebarMenu> {data.navSecondary.map((item) => ( <SidebarMenuItem key={item.title}> <SidebarMenuButton asChild size="sm"> <a href={item.url}> {item.icon} <span>{item.title}</span> </a> </SidebarMenuButton> </SidebarMenuItem> ))} </SidebarMenu> </SidebarGroupContent> </SidebarGroup> </SidebarContent> <SidebarRail /> </Sidebar> <SidebarInset> <header className="flex h-16 shrink-0 items-center gap-2 border-b px-4"> <SidebarTrigger className="-ml-1" /> </header> <div className="flex flex-1 flex-col gap-4 p-4"> <div className="grid auto-rows-min gap-4 md:grid-cols-3"> <div className="aspect-video rounded-xl bg-muted/50" /> <div className="aspect-video rounded-xl bg-muted/50" /> <div className="aspect-video rounded-xl bg-muted/50" /> </div> <div className="min-h-[100vh] flex-1 rounded-xl bg-muted/50 md:min-h-min" /> </div> </SidebarInset> </SidebarProvider> )}Adapted from the shadcn/ui Sidebar (MIT).
