Sidebar - Shadcn - Ui
Sidebar - Shadcn - Ui
⌘ K
Docs Sidebar
Sidebar
A composable, themeable and customizable sidebar component.
Sidebars are one of the most complex components to build. They are central to any
I don't like building sidebars. So I built 30+ of them. All kinds of configurations. Then I
We now have a solid foundation to build on top of. Composable. Themeable. Customizable.
CLI Manual
The command above should install the colors for you. If not, copy and paste the
app/globals.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: 224.3 76.3% 48%;
--sidebar-primary-foreground: 0 0% 100%;
--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%;
}
}
Structure
SidebarHeader and SidebarFooter - Sticky at the top and bottom of the sidebar.
app/layout.tsx
components/app-sidebar.tsx
1 import {
2 Sidebar,
3 SidebarContent,
4 SidebarFooter,
5 SidebarGroup,
6 SidebarHeader,
7 } from "@/components/ui/sidebar"
8
Let's start with the most basic sidebar. A collapsible sidebar with a menu.
app/layout.tsx
components/app-sidebar.tsx
components/app-sidebar.tsx
3 import {
4 Sidebar,
5 SidebarContent,
6 SidebarGroup,
7 SidebarGroupContent,
8 SidebarGroupLabel,
9 SidebarMenu,
10 SidebarMenuButton,
11 SidebarMenuItem,
12 } from "@/components/ui/sidebar"
13
14 // Menu items.
15 const items = [
16 {
17 title: "Home",
18 url: "#",
19 icon: Home,
20 },
21 {
22 title: "Inbox",
23 url: "#",
24 icon: Inbox,
25 },
4 You've created 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
If you need to change the code in sidebar.tsx , you are encouraged to do so. The code
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
Props
Width
If you have a single sidebar in your application, you can use the SIDEBAR_WIDTH and
components/ui/sidebar.tsx
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-
components/ui/sidebar.tsx
1 <SidebarProvider
2 style={{
3 "--sidebar-width": "20rem",
4 "--sidebar-width-mobile": "20rem",
5 }}
6 >
7 <Sidebar />
8 </SidebarProvider>
This will handle the width of the sidebar but also the layout spacing.
Keyboard Shortcut
To trigger the sidebar, you use the cmd+b keyboard shortcut on Mac and ctrl+b on
Windows.
variable.
components/ui/sidebar.tsx
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.
this:
app/layout.tsx
10 return (
11 <SidebarProvider defaultOpen={defaultOpen}>
12 <AppSidebar />
13 <main>
14 <SidebarTrigger />
15 {children}
16 </main>
17 </SidebarProvider>
18 )
19 }
You can change the name of the cookie by updating the SIDEBAR_COOKIE_NAME variable in
sidebar.tsx .
components/ui/sidebar.tsx
Sidebar
side
variant
Note: If you use the inset variant, remember to wrap your main content in a SidebarInset
component.
1 <SidebarProvider>
2 <Sidebar variant="inset" />
3 <SidebarInset>
4 <main>{children}</main>
5 </SidebarInset>
6 </SidebarProvider>
collapsible
Prop Description
useSidebar
SidebarHeader
components/app-sidebar.tsx
1 <Sidebar>
2 <SidebarHeader>
3 <SidebarMenu>
4 <SidebarMenuItem>
5 <DropdownMenu>
6 <DropdownMenuTrigger asChild>
7 <SidebarMenuButton>
8 Select Workspace
9 <ChevronDown className="ml-auto" />
10 </SidebarMenuButton>
11 </DropdownMenuTrigger>
12 <DropdownMenuContent className="w-[--radix-popper-anchor-width]"
13 <DropdownMenuItem>
14 <span>Acme Inc</span>
15 </DropdownMenuItem>
16 <DropdownMenuItem>
17 <span>Acme Corp.</span>
18 </DropdownMenuItem>
19 </DropdownMenuContent>
20 </DropdownMenu>
21 </SidebarMenuItem>
22 </SidebarMenu>
23 </SidebarHeader>
24 </Sidebar>
SidebarFooter
components/app-sidebar.tsx
SidebarContent
The SidebarContent component is used to wrap the content of the sidebar. This is where
SidebarGroup
SidebarGroupAction .
A sidebar group.
Collapsible SidebarGroup
SidebarGroupAction
SidebarMenu
1 <Sidebar>
2 <SidebarContent>
3 <SidebarGroup>
4 <SidebarGroupLabel>Projects</SidebarGroupLabel>
5 <SidebarGroupContent>
6 <SidebarMenu>
7 {projects.map((project) => (
8 <SidebarMenuItem key={project.name}>
9 <SidebarMenuButton asChild>
10 <a href={project.url}>
11 <project.icon />
12 <span>{project.name}</span>
13 </a>
14 </SidebarMenuButton>
15 </SidebarMenuItem>
16 ))}
17 </SidebarMenu>
18 </SidebarGroupContent>
19 </SidebarGroup>
20 </SidebarContent>
21 </Sidebar>
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
1 <SidebarMenuButton asChild>
2 <a href="#">Home</a>
3 </SidebarMenuButton>
You can render an icon and a truncated label inside the button. Remember to wrap the label
in a <span> .
1 <SidebarMenuButton asChild>
2 <a href="#">
3 <Home />
4 <span>Home</span>
5 </a>
6 </SidebarMenuButton>
isActive
SidebarMenuItem .
This button works independently of the SidebarMenuButton i.e you can have the
1 <SidebarMenuItem>
2 <SidebarMenuButton asChild>
3 <a href="#">
4 <Home />
5 <span>Home</span>
6 </a>
7 </SidebarMenuButton>
8 <SidebarMenuAction>
9 <Plus /> <span className="sr-only">Add Project</span>
10 </SidebarMenuAction>
11 </SidebarMenuItem>
DropdownMenu
1 <SidebarMenuItem>
2 <SidebarMenuButton asChild>
3 <a href="#">
4 <Home />
5 <span>Home</span>
6 </a>
7 </SidebarMenuButton>
8 <DropdownMenu>
9 <DropdownMenuTrigger asChild>
10 <SidebarMenuAction>
11 <MoreHorizontal />
12 </SidebarMenuAction>
13 </DropdownMenuTrigger>
14 <DropdownMenuContent side="right" align="start">
15 <DropdownMenuItem>
16 <span>Edit Project</span>
17 </DropdownMenuItem>
18 <DropdownMenuItem>
19 <span>Delete Project</span>
20 </DropdownMenuItem>
21 </DropdownMenuContent>
22 </DropdownMenu>
23 </SidebarMenuItem>
SidebarMenuSub
1 <SidebarMenuItem>
2 <SidebarMenuButton />
3 <SidebarMenuSub>
4 <SidebarMenuSubItem>
5 <SidebarMenuSubButton />
6 </SidebarMenuSubItem>
7 <SidebarMenuSubItem>
8 <SidebarMenuSubButton />
9 </SidebarMenuSubItem>
10 </SidebarMenuSub>
11 </SidebarMenuItem>
Collapsible SidebarMenu
components in a Collapsible .
A collapsible sidebar menu.
1 <SidebarMenu>
2 <Collapsible defaultOpen className="group/collapsible">
3 <SidebarMenuItem>
4 <CollapsibleTrigger asChild>
5 <SidebarMenuButton />
6 </CollapsibleTrigger>
7 <CollapsibleContent>
8 <SidebarMenuSub>
9 <SidebarMenuSubItem />
10 </SidebarMenuSub>
11 </CollapsibleContent>
12 </SidebarMenuItem>
13 </Collapsible>
14 </SidebarMenu>
SidebarMenuBadge
The SidebarMenuBadge component is used to render a badge within a SidebarMenuItem .
1 <SidebarMenuItem>
2 <SidebarMenuButton />
3 <SidebarMenuBadge>24</SidebarMenuBadge>
4 </SidebarMenuItem>
SidebarMenuSkeleton
can use this to show a loading state when using React Server Components, SWR or react-
query.
1 function NavProjectsSkeleton() {
2 return (
3 <SidebarMenu>
4 {Array.from({ length: 5 }).map((_, index) => (
5 <SidebarMenuItem key={index}>
6 <SidebarMenuSkeleton />
7 </SidebarMenuItem>
8 ))}
9 </SidebarMenu>
10 )
11 }
SidebarSeparator
1 <Sidebar>
2 <SidebarHeader />
3 <SidebarSeparator />
4 <SidebarContent>
5 <SidebarGroup />
6 <SidebarSeparator />
7 <SidebarGroup />
8 </SidebarContent>
9 </Sidebar>
SidebarTrigger
Use the SidebarTrigger component to render a button that toggles the sidebar.
1 <SidebarProvider>
2 <Sidebar />
3 <main>
4 <SidebarTrigger />
5 </main>
6 </SidebarProvider>
Custom Trigger
SidebarRail
The SidebarRail component is used to render a rail within a Sidebar . This rail can be
1 <Sidebar>
2 <SidebarHeader />
3 <SidebarContent>
4 <SidebarGroup />
5 </SidebarContent>
6 <SidebarFooter />
7 <SidebarRail />
8 </Sidebar>
Data Fetching
Server Components.
1 function NavProjectsSkeleton() {
2 return (
3 <SidebarMenu>
4 {Array.from({ length: 5 }).map((_, index) => (
5 <SidebarMenuItem key={index}>
6 <SidebarMenuSkeleton showIcon />
7 </SidebarMenuItem>
8 ))}
9 </SidebarMenu>
10 )
11 }
4 return (
5 <SidebarMenu>
6 {projects.map((project) => (
7 <SidebarMenuItem key={project.name}>
8 <SidebarMenuButton asChild>
9 <a href={project.url}>
10 <project.icon />
11 <span>{project.name}</span>
12 </a>
13 </SidebarMenuButton>
14 </SidebarMenuItem>
15 ))}
16 </SidebarMenu>
17 )
18 }
1 function AppSidebar() {
2 return (
3 <Sidebar>
4 <SidebarContent>
5 <SidebarGroup>
6 <SidebarGroupLabel>Projects</SidebarGroupLabel>
7 <SidebarGroupContent>
8 <React.Suspense fallback={<NavProjectsSkeleton />}>
9 <NavProjects />
10 </React.Suspense>
11 </SidebarGroupContent>
12 </SidebarGroup>
13 </SidebarContent>
14 </Sidebar>
15 )
16 }
SWR and React Query
SWR
1 function NavProjects() {
2 const { data, isLoading } = useSWR("/api/projects", fetcher)
3
4 if (isLoading) {
5 return (
6 <SidebarMenu>
7 {Array.from({ length: 5 }).map((_, index) => (
8 <SidebarMenuItem key={index}>
9 <SidebarMenuSkeleton showIcon />
10 </SidebarMenuItem>
11 ))}
12 </SidebarMenu>
13 )
14 }
15
16 if (!data) {
17 return ...
18 }
19
20 return (
21 <SidebarMenu>
22 {data.map((project) => (
23 <SidebarMenuItem key={project.name}>
24 <SidebarMenuButton asChild>
25 <a href={project.url}>
26 <project.icon />
{ j t } /
React Query
1 function NavProjects() {
2 const { data, isLoading } = useQuery()
3
4 if (isLoading) {
5 return (
6 <SidebarMenu>
7 {Array.from({ length: 5 }).map((_, index) => (
8 <SidebarMenuItem key={index}>
9 <SidebarMenuSkeleton showIcon />
10 </SidebarMenuItem>
11 ))}
12 </SidebarMenu>
13 )
14 }
15
16 if (!data) {
17 return ...
18 }
19
20 return (
21 <SidebarMenu>
22 {data.map((project) => (
23 <SidebarMenuItem key={project.name}>
24 <SidebarMenuButton asChild>
25 <a href={project.url}>
26 <project.icon />
Controlled Sidebar
4 return (
5 <SidebarProvider open={open} onOpenChange={setOpen}>
6 <Sidebar />
7 </SidebarProvider>
8 )
9 }
Theming
@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.
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.
<Sidebar collapsible="icon">
<SidebarContent>
<SidebarGroup className="group-data-[collapsible=icon]:hidden" />
</SidebarContent>
</Sidebar>
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.
<SidebarMenuItem>
<SidebarMenuButton />
<SidebarMenuAction className="peer-data-[active=true]/menu-button:opacity-100
</SidebarMenuItem>
You can find more tips on using states for styling in this Twitter thread.
Changelog
Manual Accordion