---
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
CLIManualRun 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`.
## 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 IncAcme Corp.
)
}
```
A sidebar header with a dropdown menu.
```tsx showLineNumbers title="components/app-sidebar.tsx"
Select Workspace
Acme IncAcme 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
AccountBillingSign out
)
}
```
A sidebar footer with a dropdown menu.
```tsx showLineNumbers title="components/app-sidebar.tsx"
export function AppSidebar() {
return (
Username
AccountBillingSign 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 (
ApplicationAdd 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 ProjectDesign EngineeringSales & MarketingTravel
)
}
```
A sidebar group with an action button.
```tsx showLineNumbers {5-7}
export function AppSidebar() {
return (
ProjectsAdd Project
)
}
```
## SidebarMenu
The `SidebarMenu` component is used for building a menu within a `SidebarGroup`.
A `SidebarMenu` component is composed of `SidebarMenuItem`, `SidebarMenuButton`, `` and `` components.
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
HomeAdd 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}MoreEdit ProjectDelete Project
))}
)
}
```
A sidebar menu action with a dropdown menu.
```tsx showLineNumbers
HomeEdit ProjectDelete 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.")
```