--- title: Sidebar description: A composable, themeable and customizable sidebar component. component: true ---
```tsx import { AppSidebar } from "@/components/blocks/sidebar-07/components/app-sidebar" import { Breadcrumb, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, } from "@/components/ui/breadcrumb" import { Separator } from "@/components/ui/separator" import { SidebarInset, SidebarProvider, SidebarTrigger, } from "@/components/ui/sidebar" export function Page() { return (
Building Your Application Data Fetching
) } ```
A sidebar that collapses to icons.
Sidebars are one of the most complex components to build. They are central to any application and often contain a lot of moving parts. I don't like building sidebars. So I built 30+ of them. All kinds of configurations. Then I extracted the core components into `sidebar.tsx`. We now have a solid foundation to build on top of. Composable. Themeable. Customizable. [Browse the Blocks Library](/blocks). ## Installation CLI Manual Run the following command to install `sidebar.tsx` ```bash npx shadcn@latest add sidebar ``` Add the following colors to your CSS file The command above should install the colors for you. If not, copy and paste the following in your CSS file. We'll go over the colors later in the [theming section](/docs/components/sidebar#theming). ```css showLineNumbers title="app/globals.css" @layer base { :root { --sidebar: oklch(0.985 0 0); --sidebar-foreground: oklch(0.145 0 0); --sidebar-primary: oklch(0.205 0 0); --sidebar-primary-foreground: oklch(0.985 0 0); --sidebar-accent: oklch(0.97 0 0); --sidebar-accent-foreground: oklch(0.205 0 0); --sidebar-border: oklch(0.922 0 0); --sidebar-ring: oklch(0.708 0 0); } .dark { --sidebar: oklch(0.205 0 0); --sidebar-foreground: oklch(0.985 0 0); --sidebar-primary: oklch(0.488 0.243 264.376); --sidebar-primary-foreground: oklch(0.985 0 0); --sidebar-accent: oklch(0.269 0 0); --sidebar-accent-foreground: oklch(0.985 0 0); --sidebar-border: oklch(1 0 0 / 10%); --sidebar-ring: oklch(0.439 0 0); } } ``` Copy and paste the following code into your project. Update the import paths to match your project setup. Add the following colors to your CSS file We'll go over the colors later in the [theming section](/docs/components/sidebar#theming). ```css showLineNumbers title="app/globals.css" @layer base { :root { --sidebar: oklch(0.985 0 0); --sidebar-foreground: oklch(0.145 0 0); --sidebar-primary: oklch(0.205 0 0); --sidebar-primary-foreground: oklch(0.985 0 0); --sidebar-accent: oklch(0.97 0 0); --sidebar-accent-foreground: oklch(0.205 0 0); --sidebar-border: oklch(0.922 0 0); --sidebar-ring: oklch(0.708 0 0); } .dark { --sidebar: oklch(0.205 0 0); --sidebar-foreground: oklch(0.985 0 0); --sidebar-primary: oklch(0.488 0.243 264.376); --sidebar-primary-foreground: oklch(0.985 0 0); --sidebar-accent: oklch(0.269 0 0); --sidebar-accent-foreground: oklch(0.985 0 0); --sidebar-border: oklch(1 0 0 / 10%); --sidebar-ring: oklch(0.439 0 0); } } ``` ## Structure A `Sidebar` component is composed of the following parts: - `SidebarProvider` - Handles collapsible state. - `Sidebar` - The sidebar container. - `SidebarHeader` and `SidebarFooter` - Sticky at the top and bottom of the sidebar. - `SidebarContent` - Scrollable content. - `SidebarGroup` - Section within the `SidebarContent`. - `SidebarTrigger` - Trigger for the `Sidebar`. Sidebar Structure Sidebar Structure ## Usage ```tsx showLineNumbers title="app/layout.tsx" import { SidebarProvider, SidebarTrigger } from "@/components/ui/sidebar" import { AppSidebar } from "@/components/app-sidebar" export default function Layout({ children }: { children: React.ReactNode }) { return (
{children}
) } ``` ```tsx showLineNumbers title="components/app-sidebar.tsx" import { Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarHeader, } from "@/components/ui/sidebar" export function AppSidebar() { return ( ) } ``` ## Your First Sidebar Let's start with the most basic sidebar. A collapsible sidebar with a menu. Add a `SidebarProvider` and `SidebarTrigger` at the root of your application. ```tsx showLineNumbers title="app/layout.tsx" import { SidebarProvider, SidebarTrigger } from "@/components/ui/sidebar" import { AppSidebar } from "@/components/app-sidebar" export default function Layout({ children }: { children: React.ReactNode }) { return (
{children}
) } ``` Create a new sidebar component at `components/app-sidebar.tsx`. ```tsx showLineNumbers title="components/app-sidebar.tsx" import { Sidebar, SidebarContent } from "@/components/ui/sidebar" export function AppSidebar() { return ( ) } ``` Now, let's add a `SidebarMenu` to the sidebar. We'll use the `SidebarMenu` component in a `SidebarGroup`. ```tsx showLineNumbers title="components/app-sidebar.tsx" import { Calendar, Home, Inbox, Search, Settings } from "lucide-react" import { Sidebar, SidebarContent, SidebarGroup, SidebarGroupContent, SidebarGroupLabel, SidebarMenu, SidebarMenuButton, SidebarMenuItem, } from "@/components/ui/sidebar" // Menu items. const items = [ { title: "Home", url: "#", icon: Home, }, { title: "Inbox", url: "#", icon: Inbox, }, { title: "Calendar", url: "#", icon: Calendar, }, { title: "Search", url: "#", icon: Search, }, { title: "Settings", url: "#", icon: Settings, }, ] export function AppSidebar() { return ( Application {items.map((item) => ( {item.title} ))} ) } ``` You've created your first sidebar. You should see something like this:
```tsx "use client" import { CalendarIcon, HomeIcon, InboxIcon, SearchIcon, SettingsIcon, } from "lucide-react" import { Sidebar, SidebarContent, SidebarGroup, SidebarGroupContent, SidebarGroupLabel, SidebarInset, SidebarMenu, SidebarMenuButton, SidebarMenuItem, SidebarProvider, SidebarTrigger, } from "@/components/ui/sidebar" // Menu items. const items = [ { title: "Home", url: "#", icon: HomeIcon, }, { title: "Inbox", url: "#", icon: InboxIcon, }, { title: "Calendar", url: "#", icon: CalendarIcon, }, { title: "Search", url: "#", icon: SearchIcon, }, { title: "Settings", url: "#", icon: SettingsIcon, }, ] export function AppSidebar() { return ( Application {items.map((item) => ( {item.title} ))}
) } ```
Your first sidebar.
## Components The components in `sidebar.tsx` are built to be composable i.e you build your sidebar by putting the provided components together. They also compose well with other shadcn/ui components such as `DropdownMenu`, `Collapsible` or `Dialog` etc. **If you need to change the code in `sidebar.tsx`, you are encouraged to do so. The code is yours. Use `sidebar.tsx` as a starting point and build your own.** In the next sections, we'll go over each component and how to use them. ## SidebarProvider The `SidebarProvider` component is used to provide the sidebar context to the `Sidebar` component. You should always wrap your application in a `SidebarProvider` component. ### Props | Name | Type | Description | | -------------- | ------------------------- | -------------------------------------------- | | `defaultOpen` | `boolean` | Default open state of the sidebar. | | `open` | `boolean` | Open state of the sidebar (controlled). | | `onOpenChange` | `(open: boolean) => void` | Sets open state of the sidebar (controlled). | ### Width If you have a single sidebar in your application, you can use the `SIDEBAR_WIDTH` and `SIDEBAR_WIDTH_MOBILE` variables in `sidebar.tsx` to set the width of the sidebar. ```tsx showLineNumbers title="components/ui/sidebar.tsx" const SIDEBAR_WIDTH = "16rem" const SIDEBAR_WIDTH_MOBILE = "18rem" ``` For multiple sidebars in your application, you can use the `style` prop to set the width of the sidebar. To set the width of the sidebar, you can use the `--sidebar-width` and `--sidebar-width-mobile` CSS variables in the `style` prop. ```tsx showLineNumbers title="components/ui/sidebar.tsx" ``` This will handle the width of the sidebar but also the layout spacing. ### Keyboard Shortcut The `SIDEBAR_KEYBOARD_SHORTCUT` variable is used to set the keyboard shortcut used to open and close the sidebar. To trigger the sidebar, you use the `cmd+b` keyboard shortcut on Mac and `ctrl+b` on Windows. You can change the keyboard shortcut by updating the `SIDEBAR_KEYBOARD_SHORTCUT` variable. ```tsx showLineNumbers title="components/ui/sidebar.tsx" const SIDEBAR_KEYBOARD_SHORTCUT = "b" ``` ### Persisted State The `SidebarProvider` supports persisting the sidebar state across page reloads and server-side rendering. It uses cookies to store the current state of the sidebar. When the sidebar state changes, a default cookie named `sidebar_state` is set with the current open/closed state. This cookie is then read on subsequent page loads to restore the sidebar state. To persist sidebar state in Next.js, set up your `SidebarProvider` in `app/layout.tsx` like this: ```tsx showLineNumbers title="app/layout.tsx" import { cookies } from "next/headers" import { SidebarProvider, SidebarTrigger } from "@/components/ui/sidebar" import { AppSidebar } from "@/components/app-sidebar" export async function Layout({ children }: { children: React.ReactNode }) { const cookieStore = await cookies() const defaultOpen = cookieStore.get("sidebar_state")?.value === "true" return (
{children}
) } ``` You can change the name of the cookie by updating the `SIDEBAR_COOKIE_NAME` variable in `sidebar.tsx`. ```tsx showLineNumbers title="components/ui/sidebar.tsx" const SIDEBAR_COOKIE_NAME = "sidebar_state" ``` ## Sidebar The main `Sidebar` component used to render a collapsible sidebar. ```tsx showLineNumbers import { Sidebar } from "@/components/ui/sidebar" export function AppSidebar() { return } ``` ### Props | Property | Type | Description | | ------------- | --------------------------------- | --------------------------------- | | `side` | `left` or `right` | The side of the sidebar. | | `variant` | `sidebar`, `floating`, or `inset` | The variant of the sidebar. | | `collapsible` | `offcanvas`, `icon`, or `none` | Collapsible state of the sidebar. | ### side Use the `side` prop to change the side of the sidebar. Available options are `left` and `right`. ```tsx showLineNumbers import { Sidebar } from "@/components/ui/sidebar" export function AppSidebar() { return } ``` ### variant Use the `variant` prop to change the variant of the sidebar. Available options are `sidebar`, `floating` and `inset`. ```tsx showLineNumbers import { Sidebar } from "@/components/ui/sidebar" export function AppSidebar() { return } ``` **Note:** If you use the `inset` variant, remember to wrap your main content in a `SidebarInset` component. ```tsx showLineNumbers
{children}
``` ### collapsible Use the `collapsible` prop to make the sidebar collapsible. Available options are `offcanvas`, `icon` and `none`. ```tsx showLineNumbers import { Sidebar } from "@/components/ui/sidebar" export function AppSidebar() { return } ``` | Prop | Description | | ----------- | ------------------------------------------------------------ | | `offcanvas` | A collapsible sidebar that slides in from the left or right. | | `icon` | A sidebar that collapses to icons. | | `none` | A non-collapsible sidebar. | ## useSidebar The `useSidebar` hook is used to control the sidebar. ```tsx showLineNumbers import { useSidebar } from "@/components/ui/sidebar" export function AppSidebar() { const { state, open, setOpen, openMobile, setOpenMobile, isMobile, toggleSidebar, } = useSidebar() } ``` | Property | Type | Description | | --------------- | ------------------------- | --------------------------------------------- | | `state` | `expanded` or `collapsed` | The current state of the sidebar. | | `open` | `boolean` | Whether the sidebar is open. | | `setOpen` | `(open: boolean) => void` | Sets the open state of the sidebar. | | `openMobile` | `boolean` | Whether the sidebar is open on mobile. | | `setOpenMobile` | `(open: boolean) => void` | Sets the open state of the sidebar on mobile. | | `isMobile` | `boolean` | Whether the sidebar is on mobile. | | `toggleSidebar` | `() => void` | Toggles the sidebar. Desktop and mobile. | ## SidebarHeader Use the `SidebarHeader` component to add a sticky header to the sidebar. The following example adds a `` to the `SidebarHeader`.
```tsx "use client" import { ChevronDownIcon } from "lucide-react" import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu" import { Sidebar, SidebarHeader, SidebarInset, SidebarMenu, SidebarMenuButton, SidebarMenuItem, SidebarProvider, SidebarTrigger, } from "@/components/ui/sidebar" export function AppSidebar() { return ( Select Workspace Acme Inc Acme Corp.
) } ```
A sidebar header with a dropdown menu.
```tsx showLineNumbers title="components/app-sidebar.tsx" Select Workspace Acme Inc Acme Corp. ``` ## SidebarFooter Use the `SidebarFooter` component to add a sticky footer to the sidebar. The following example adds a `` to the `SidebarFooter`.
```tsx "use client" import { ChevronUpIcon } from "lucide-react" import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu" import { Sidebar, SidebarContent, SidebarFooter, SidebarHeader, SidebarInset, SidebarMenu, SidebarMenuButton, SidebarMenuItem, SidebarProvider, SidebarTrigger, } from "@/components/ui/sidebar" export function AppSidebar() { return ( Username Account Billing Sign out
) } ```
A sidebar footer with a dropdown menu.
```tsx showLineNumbers title="components/app-sidebar.tsx" export function AppSidebar() { return ( Username Account Billing Sign out ) } ``` ## SidebarContent The `SidebarContent` component is used to wrap the content of the sidebar. This is where you add your `SidebarGroup` components. It is scrollable. ```tsx showLineNumbers import { Sidebar, SidebarContent } from "@/components/ui/sidebar" export function AppSidebar() { return ( ) } ``` ## SidebarGroup Use the `SidebarGroup` component to create a section within the sidebar. A `SidebarGroup` has a `SidebarGroupLabel`, a `SidebarGroupContent` and an optional `SidebarGroupAction`.
```tsx "use client" import { LifeBuoyIcon, SendIcon } from "lucide-react" import { Sidebar, SidebarContent, SidebarGroup, SidebarGroupContent, SidebarGroupLabel, SidebarMenu, SidebarMenuButton, SidebarMenuItem, SidebarProvider, } from "@/components/ui/sidebar" export function AppSidebar() { return ( Help Support Feedback ) } ```
A sidebar group.
```tsx showLineNumbers import { Sidebar, SidebarContent, SidebarGroup } from "@/components/ui/sidebar" export function AppSidebar() { return ( Application Add Project ) } ``` ## Collapsible SidebarGroup To make a `SidebarGroup` collapsible, wrap it in a `Collapsible`.
```tsx "use client" import { ChevronDownIcon, LifeBuoyIcon, SendIcon } from "lucide-react" import { Collapsible, CollapsibleContent, CollapsibleTrigger, } from "@/components/ui/collapsible" import { Sidebar, SidebarContent, SidebarGroup, SidebarGroupContent, SidebarGroupLabel, SidebarMenu, SidebarMenuButton, SidebarMenuItem, SidebarProvider, } from "@/components/ui/sidebar" export function AppSidebar() { return ( Help Support Feedback ) } ```
A collapsible sidebar group.
```tsx showLineNumbers export function AppSidebar() { return ( Help ) } ``` **Note:** We wrap the `CollapsibleTrigger` in a `SidebarGroupLabel` to render a button. ## SidebarGroupAction Use the `SidebarGroupAction` component to add an action button to the `SidebarGroup`.
```tsx "use client" import { FrameIcon, MapIcon, PieChartIcon, PlusIcon } from "lucide-react" import { toast, Toaster } from "sonner" import { Sidebar, SidebarContent, SidebarGroup, SidebarGroupAction, SidebarGroupContent, SidebarGroupLabel, SidebarMenu, SidebarMenuButton, SidebarMenuItem, SidebarProvider, } from "@/components/ui/sidebar" export function AppSidebar() { return ( Projects toast("You clicked the group action!")} > Add Project Design Engineering Sales & Marketing Travel ) } ```
A sidebar group with an action button.
```tsx showLineNumbers {5-7} export function AppSidebar() { return ( Projects Add Project ) } ``` ## SidebarMenu The `SidebarMenu` component is used for building a menu within a `SidebarGroup`. A `SidebarMenu` component is composed of `SidebarMenuItem`, `SidebarMenuButton`, `` and `` components. Sidebar Menu Sidebar Menu Here's an example of a `SidebarMenu` component rendering a list of projects.
```tsx "use client" import { FrameIcon, LifeBuoyIcon, MapIcon, PieChartIcon, SendIcon, } from "lucide-react" import { Sidebar, SidebarContent, SidebarGroup, SidebarGroupContent, SidebarGroupLabel, SidebarMenu, SidebarMenuButton, SidebarMenuItem, SidebarProvider, } from "@/components/ui/sidebar" const projects = [ { name: "Design Engineering", url: "#", icon: FrameIcon, }, { name: "Sales & Marketing", url: "#", icon: PieChartIcon, }, { name: "Travel", url: "#", icon: MapIcon, }, { name: "Support", url: "#", icon: LifeBuoyIcon, }, { name: "Feedback", url: "#", icon: SendIcon, }, ] export function AppSidebar() { return ( Projects {projects.map((project) => ( {project.name} ))} ) } ```
A sidebar menu with a list of projects.
```tsx showLineNumbers Projects {projects.map((project) => ( {project.name} ))} ``` ## SidebarMenuButton The `SidebarMenuButton` component is used to render a menu button within a `SidebarMenuItem`. ### Link or Anchor By default, the `SidebarMenuButton` renders a button but you can use the `asChild` prop to render a different component such as a `Link` or an `a` tag. ```tsx showLineNumbers Home ``` ### Icon and Label You can render an icon and a truncated label inside the button. Remember to wrap the label in a ``. ```tsx showLineNumbers Home ``` ### isActive Use the `isActive` prop to mark a menu item as active. ```tsx showLineNumbers Home ``` ## SidebarMenuAction The `SidebarMenuAction` component is used to render a menu action within a `SidebarMenuItem`. This button works independently of the `SidebarMenuButton` i.e you can have the `` as a clickable link and the `` as a button. ```tsx showLineNumbers Home Add Project ``` ### DropdownMenu Here's an example of a `SidebarMenuAction` component rendering a `DropdownMenu`.
```tsx "use client" import { FrameIcon, LifeBuoyIcon, MapIcon, MoreHorizontalIcon, PieChartIcon, SendIcon, } from "lucide-react" import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu" import { Sidebar, SidebarContent, SidebarGroup, SidebarGroupContent, SidebarGroupLabel, SidebarMenu, SidebarMenuAction, SidebarMenuButton, SidebarMenuItem, SidebarProvider, } from "@/components/ui/sidebar" const projects = [ { name: "Design Engineering", url: "#", icon: FrameIcon, }, { name: "Sales & Marketing", url: "#", icon: PieChartIcon, }, { name: "Travel", url: "#", icon: MapIcon, }, { name: "Support", url: "#", icon: LifeBuoyIcon, }, { name: "Feedback", url: "#", icon: SendIcon, }, ] export function AppSidebar() { return ( Projects {projects.map((project) => ( {project.name} More Edit Project Delete Project ))} ) } ```
A sidebar menu action with a dropdown menu.
```tsx showLineNumbers Home Edit Project Delete Project ``` ## SidebarMenuSub The `SidebarMenuSub` component is used to render a submenu within a `SidebarMenu`. Use `` and `` to render a submenu item.
```tsx "use client" import { Sidebar, SidebarContent, SidebarGroup, SidebarGroupContent, SidebarMenu, SidebarMenuButton, SidebarMenuItem, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarProvider, } from "@/components/ui/sidebar" const items = [ { title: "Getting Started", url: "#", items: [ { title: "Installation", url: "#", }, { title: "Project Structure", url: "#", }, ], }, { title: "Building 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: "#", }, ], }, ] export function AppSidebar() { return ( {items.map((item, index) => ( {item.title} {item.items.map((subItem, subIndex) => ( {subItem.title} ))} ))} ) } ```
A sidebar menu with a submenu.
```tsx showLineNumbers ``` ## Collapsible SidebarMenu To make a `SidebarMenu` component collapsible, wrap it and the `SidebarMenuSub` components in a `Collapsible`.
```tsx "use client" import { ChevronRightIcon } from "lucide-react" import { Collapsible, CollapsibleContent, CollapsibleTrigger, } from "@/components/ui/collapsible" import { Sidebar, SidebarContent, SidebarGroup, SidebarGroupContent, SidebarMenu, SidebarMenuButton, SidebarMenuItem, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarProvider, } from "@/components/ui/sidebar" const items = [ { title: "Getting Started", url: "#", items: [ { title: "Installation", url: "#", }, { title: "Project Structure", url: "#", }, ], }, { title: "Building 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: "#", }, ], }, ] export function AppSidebar() { return ( {items.map((item, index) => ( {item.title} {item.items.map((subItem, subIndex) => ( {subItem.title} ))} ))} ) } ```
A collapsible sidebar menu.
```tsx showLineNumbers ``` ## SidebarMenuBadge The `SidebarMenuBadge` component is used to render a badge within a `SidebarMenuItem`.
```tsx "use client" import { FrameIcon, LifeBuoyIcon, MapIcon, PieChartIcon, SendIcon, } from "lucide-react" import { Sidebar, SidebarContent, SidebarGroup, SidebarGroupContent, SidebarGroupLabel, SidebarMenu, SidebarMenuBadge, SidebarMenuButton, SidebarMenuItem, SidebarProvider, } from "@/components/ui/sidebar" const projects = [ { name: "Design Engineering", url: "#", icon: FrameIcon, badge: "24", }, { name: "Sales & Marketing", url: "#", icon: PieChartIcon, badge: "12", }, { name: "Travel", url: "#", icon: MapIcon, badge: "3", }, { name: "Support", url: "#", icon: LifeBuoyIcon, badge: "21", }, { name: "Feedback", url: "#", icon: SendIcon, badge: "8", }, ] export function AppSidebar() { return ( Projects {projects.map((project) => ( {project.name} {project.badge} ))} ) } ```
A sidebar menu with a badge.
```tsx showLineNumbers 24 ``` ## SidebarMenuSkeleton The `SidebarMenuSkeleton` component is used to render a skeleton for a `SidebarMenu`. You can use this to show a loading state when using React Server Components, SWR or react-query. ```tsx showLineNumbers function NavProjectsSkeleton() { return ( {Array.from({ length: 5 }).map((_, index) => ( ))} ) } ``` ## SidebarSeparator The `SidebarSeparator` component is used to render a separator within a `Sidebar`. ```tsx showLineNumbers ``` ## SidebarTrigger Use the `SidebarTrigger` component to render a button that toggles the sidebar. The `SidebarTrigger` component must be used within a `SidebarProvider`. ```tsx showLineNumbers
``` ### Custom Trigger To create a custom trigger, you can use the `useSidebar` hook. ```tsx showLineNumbers import { useSidebar } from "@/components/ui/sidebar" export function CustomTrigger() { const { toggleSidebar } = useSidebar() return } ``` ## SidebarRail The `SidebarRail` component is used to render a rail within a `Sidebar`. This rail can be used to toggle the sidebar. ```tsx showLineNumbers ``` ## Data Fetching ### React Server Components Here's an example of a `SidebarMenu` component rendering a list of projects using React Server Components.
```tsx import * as React from "react" import { FrameIcon, LifeBuoyIcon, MapIcon, PieChartIcon, SendIcon, } from "lucide-react" import { Sidebar, SidebarContent, SidebarGroup, SidebarGroupContent, SidebarGroupLabel, SidebarMenu, SidebarMenuButton, SidebarMenuItem, SidebarMenuSkeleton, SidebarProvider, } from "@/components/ui/sidebar" const projects = [ { name: "Design Engineering", url: "#", icon: FrameIcon, badge: "24", }, { name: "Sales & Marketing", url: "#", icon: PieChartIcon, badge: "12", }, { name: "Travel", url: "#", icon: MapIcon, badge: "3", }, { name: "Support", url: "#", icon: LifeBuoyIcon, badge: "21", }, { name: "Feedback", url: "#", icon: SendIcon, badge: "8", }, ] // Dummy fetch function async function fetchProjects() { await new Promise((resolve) => setTimeout(resolve, 3000)) return projects } export function AppSidebar() { return ( Projects }> ) } function NavProjectsSkeleton() { return ( {Array.from({ length: 5 }).map((_, index) => ( ))} ) } async function NavProjects() { const projects = await fetchProjects() return ( {projects.map((project) => ( {project.name} ))} ) } ```
A sidebar menu using React Server Components.
```tsx showLineNumbers {6} title="Skeleton to show loading state." function NavProjectsSkeleton() { return ( {Array.from({ length: 5 }).map((_, index) => ( ))} ) } ``` ```tsx showLineNumbers {2} title="Server component fetching data." async function NavProjects() { const projects = await fetchProjects() return ( {projects.map((project) => ( {project.name} ))} ) } ``` ```tsx showLineNumbers {8-10} title="Usage with React Suspense." function AppSidebar() { return ( Projects }> ) } ``` ### SWR and React Query You can use the same approach with [SWR](https://swr.vercel.app/) or [react-query](https://tanstack.com/query/latest/docs/framework/react/overview). ```tsx showLineNumbers title="SWR" function NavProjects() { const { data, isLoading } = useSWR("/api/projects", fetcher) if (isLoading) { return ( {Array.from({ length: 5 }).map((_, index) => ( ))} ) } if (!data) { return ... } return ( {data.map((project) => ( {project.name} ))} ) } ``` ```tsx showLineNumbers title="React Query" function NavProjects() { const { data, isLoading } = useQuery() if (isLoading) { return ( {Array.from({ length: 5 }).map((_, index) => ( ))} ) } if (!data) { return ... } return ( {data.map((project) => ( {project.name} ))} ) } ``` ## Controlled Sidebar Use the `open` and `onOpenChange` props to control the sidebar.
```tsx "use client" import * as React from "react" import { FrameIcon, LifeBuoyIcon, MapIcon, PanelLeftCloseIcon, PanelLeftOpenIcon, PieChartIcon, SendIcon, } from "lucide-react" import { Button } from "@/components/ui/button" import { Sidebar, SidebarContent, SidebarGroup, SidebarGroupContent, SidebarGroupLabel, SidebarInset, SidebarMenu, SidebarMenuButton, SidebarMenuItem, SidebarProvider, } from "@/components/ui/sidebar" const projects = [ { name: "Design Engineering", url: "#", icon: FrameIcon, }, { name: "Sales & Marketing", url: "#", icon: PieChartIcon, }, { name: "Travel", url: "#", icon: MapIcon, }, { name: "Support", url: "#", icon: LifeBuoyIcon, }, { name: "Feedback", url: "#", icon: SendIcon, }, ] export function AppSidebar() { const [open, setOpen] = React.useState(true) return ( Projects {projects.map((project) => ( {project.name} ))}
) } ```
A controlled sidebar.
```tsx showLineNumbers export function AppSidebar() { const [open, setOpen] = React.useState(false) return ( ) } ``` ## Theming We use the following CSS variables to theme the sidebar. ```css @layer base { :root { --sidebar-background: 0 0% 98%; --sidebar-foreground: 240 5.3% 26.1%; --sidebar-primary: 240 5.9% 10%; --sidebar-primary-foreground: 0 0% 98%; --sidebar-accent: 240 4.8% 95.9%; --sidebar-accent-foreground: 240 5.9% 10%; --sidebar-border: 220 13% 91%; --sidebar-ring: 217.2 91.2% 59.8%; } .dark { --sidebar-background: 240 5.9% 10%; --sidebar-foreground: 240 4.8% 95.9%; --sidebar-primary: 0 0% 98%; --sidebar-primary-foreground: 240 5.9% 10%; --sidebar-accent: 240 3.7% 15.9%; --sidebar-accent-foreground: 240 4.8% 95.9%; --sidebar-border: 240 3.7% 15.9%; --sidebar-ring: 217.2 91.2% 59.8%; } } ``` **We intentionally use different variables for the sidebar and the rest of the application** to make it easy to have a sidebar that is styled differently from the rest of the application. Think a sidebar with a darker shade from the main application. ## Styling Here are some tips for styling the sidebar based on different states. - **Styling an element based on the sidebar collapsible state.** The following will hide the `SidebarGroup` when the sidebar is in `icon` mode. ```tsx ``` - **Styling a menu action based on the menu button active state.** The following will force the menu action to be visible when the menu button is active. ```tsx ``` You can find more tips on using states for styling in this [Twitter thread](https://x.com/shadcn/status/1842329158879420864). ## Changelog ### 2024-10-30 Cookie handling in setOpen - [#5593](https://github.com/shadcn-ui/ui/pull/5593) - Improved setOpen callback logic in ``. Update the `setOpen` callback in `` as follows: ```tsx showLineNumbers const setOpen = React.useCallback( (value: boolean | ((value: boolean) => boolean)) => { const openState = typeof value === "function" ? value(open) : value if (setOpenProp) { setOpenProp(openState) } else { _setOpen(openState) } // This sets the cookie to keep the sidebar state. document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}` }, [setOpenProp, open] ) ``` ### 2024-10-21 Fixed `text-sidebar-foreground` - [#5491](https://github.com/shadcn-ui/ui/pull/5491) - Moved `text-sidebar-foreground` from `` to `` component. ### 2024-10-20 Typo in `useSidebar` hook. Fixed typo in `useSidebar` hook. ```diff showLineNumbers title="sidebar.tsx" - throw new Error("useSidebar must be used within a Sidebar.") + throw new Error("useSidebar must be used within a SidebarProvider.") ```