Skip to content
shadcn.io is not affiliated with official shadcn/ui

Shadcn Sidebar for React and Tailwind

A sidebar for navigation and app structure.

For full-page examples that wire the sidebar:

Browse the Sidebar Components (soon).

Installation

bunx --bun shadcn@latest add https://kit.dev/r/sidebar.json

Anatomy

SidebarProvider
├── Sidebar
│   ├── SidebarHeader
│   ├── SidebarContent
│   │   └── SidebarGroup
│   │       ├── SidebarGroupLabel
│   │       ├── SidebarGroupAction
│   │       ├── SidebarGroupContent
│   │       └── SidebarMenu
│   │           ├── SidebarMenuItem
│   │           │   ├── SidebarMenuButton
│   │           │   ├── SidebarMenuAction
│   │           │   └── SidebarMenuBadge
│   │           └── SidebarMenuSub
│   │               ├── SidebarMenuSubButton
│   │               └── SidebarMenuSubItem
│   ├── SidebarFooter
│   ├── SidebarSeparator
│   └── SidebarInput
├── SidebarTrigger
├── SidebarRail
└── SidebarInset

Structure

Piecing a Sidebar together usually means:

  • <SidebarProvider> — Owns open/collapsed state, mobile sheet state, and keyboard shortcut handling.
  • <Sidebar> — Fixed (or sheet) column: placement, variant, and collapsible behavior.
  • <SidebarHeader> / <SidebarFooter> — Pin content to the top or bottom of the column.
  • <SidebarContent> — Scrollable middle; optional scrollFade on the inner scroll area.
  • <SidebarGroup> — Labeled section inside the scroll region.
  • <SidebarTrigger> — Icon/control wired to useSidebar().toggleSidebar.
  • <SidebarInset> — Main document column beside the sidebar (required for variant="inset").

Optional helpers: <SidebarRail> (edge hit target), the <SidebarMenu> building blocks (submenus, badges, skeletons, actions)—same roles as in the upstream doc.

Usage

app/layout.tsx keeps the provider at the top level:

app/layout.tsx
import { SidebarProvider, SidebarTrigger } from "@/components/ui/sidebar";
import { AppSidebar } from "@/components/app-sidebar";

export default function Layout({ children }: React.PropsWithChildren) {
  return (
    <SidebarProvider>
      <AppSidebar />
      <main>
        <SidebarTrigger />
        {children}
      </main>
    </SidebarProvider>
  );
}

The sidebar column itself is usually a dedicated module:

components/app-sidebar.tsx
import {
  Sidebar,
  SidebarContent,
  SidebarFooter,
  SidebarGroup,
  SidebarHeader,
} from "@/components/ui/sidebar";

export function AppSidebar() {
  return (
    <Sidebar>
      <SidebarHeader />
      <SidebarContent>
        <SidebarGroup />
        <SidebarGroup />
      </SidebarContent>
      <SidebarFooter />
    </Sidebar>
  );
}

Controlled

Use the onOpenChange prop to control the sidebar open state.

"use client";

import React from "react";
import { Sidebar, SidebarProvider } from "@/components/ui/sidebar";

export const ControlledLayout = () => {
  const [open, setOpen] = React.useState(false);

  return (
    <SidebarProvider onOpenChange={setOpen} open={open}>
      <Sidebar />
    </SidebarProvider>
  );
}

Theming

Sidebar uses CSS variables to style the sidebar. See the full palette in Colors.

Variable Reference

  • --sidebar — Sidebar background
  • --sidebar-foreground — Sidebar text
  • --sidebar-primary — Active item background
  • --sidebar-accent — Hover and active states
  • --sidebar-border — Sidebar borders
  • --sidebar-ring — Focus rings

Learn more about styling in the Styling section.

Styling

React to collapse mode and peer state with utilities.

<Sidebar collapsible="icon">
  <SidebarContent>
    <SidebarGroup className="group-data-[collapsible=icon]:hidden" />
  </SidebarContent>
</Sidebar>
<SidebarMenuItem>
  <SidebarMenuButton />
  <SidebarMenuAction className="peer-data-[active=true]/menu-button:opacity-100" />
</SidebarMenuItem>

Keyboard shortcut

The toggle listens for ⌘B on macOS and Ctrl+B elsewhere (SIDEBAR_KEYBOARD_SHORTCUT in source). Match that expectation in shortcuts or help copy.

API Reference

SidebarProvider

SidebarProvider must wrap any tree that calls useSidebar or renders Sidebar / SidebarTrigger. It forwards standard div props (including className and style).

NameTypeDescription
defaultOpenbooleanInitial open state on desktop (true by default).
openbooleanControlled open flag.
onOpenChange(open: boolean) => voidFires when the open flag changes.

Width

Defaults live beside SIDEBAR_WIDTH and SIDEBAR_WIDTH_MOBILE inside the registry file. Override per layout with CSS variables on the provider:

<SidebarProvider
  style={
    {
      "--sidebar-width": "20rem",
      "--sidebar-width-mobile": "20rem",
    } as React.CSSProperties
  }
>
  <Sidebar />
</SidebarProvider>
AttributeDefault
--sidebar-width16rem
--sidebar-width-mobile18rem
--sidebar-width-icon3rem

Primary column component: desktop fixed strip + mobile sheet (via Sheet).

PropertyTypeDescription
placement"left" | "right"Which horizontal edge the column hugs (same idea as “side” in shadcn).
variant"sidebar" | "floating" | "inset"Visual treatment: flush rail, floating panel, or inset shell.
collapsible"offcanvas" | "icon" | "none"How width collapses.

Collapsible modes

ModeBehavior
offcanvasCollapses off-screen; rail can recall it.
iconShrinks to an icon rail.
noneFixed width; no collapse animation.

With variant="inset", park page content in SidebarInset so padding, radius, and background line up with the inset shell:

<SidebarProvider>
  <Sidebar variant="inset" />
  <SidebarInset>
    <main>{children}</main>
  </SidebarInset>
</SidebarProvider>

useSidebar

import { useSidebar } from "@/components/ui/sidebar";

export function Example() {
  const {
    state,
    open,
    setOpen,
    openMobile,
    setOpenMobile,
    isMobile,
    toggleSidebar,
  } = useSidebar();
}
PropertyTypeDescription
state"expanded" | "collapsed"Desktop collapse mode.
openbooleanDesktop drawer expanded.
setOpen(open: boolean) => voidSet desktop open.
openMobilebooleanMobile sheet visibility.
setOpenMobile(open: boolean) => voidControl the sheet.
isMobilebooleanBreakpoint-derived mobile flag.
toggleSidebar() => voidToggles desktop or mobile as appropriate.

SidebarHeader

Sticky top region—common pattern: workspace switcher or brand row inside a SidebarMenu.

<Sidebar>
  <SidebarHeader>
    <SidebarMenu>
      <SidebarMenuItem>
        <SidebarMenuButton>
          <span>Select workspace</span>
          <ChevronDown className="ms-auto" />
        </SidebarMenuButton>
      </SidebarMenuItem>
    </SidebarMenu>
  </SidebarHeader>
</Sidebar>

Wire menus or Menu triggers to SidebarMenuButton as needed.

SidebarFooter

Sticky bottom slot—profile, settings entry, sign-out, etc.

<Sidebar>
  <SidebarFooter>
    <SidebarMenu>
      <SidebarMenuItem>
        <SidebarMenuButton>
          <User2 /> Username
        </SidebarMenuButton>
      </SidebarMenuItem>
    </SidebarMenu>
  </SidebarFooter>
</Sidebar>

SidebarContent

Wraps scrollable groups. Pass scrollFade when you want a fade on vertical overflow (see component props in source).

<Sidebar>
  <SidebarContent>
    <SidebarGroup />
    <SidebarGroup />
  </SidebarContent>
</Sidebar>
AttributeDefault
--fade-size3rem

SidebarGroup

A titled block with optional SidebarGroupAction and SidebarGroupContent.

<SidebarGroup>
  <SidebarGroupLabel>Application</SidebarGroupLabel>
  <SidebarGroupAction>
    <Plus /> <span className="sr-only">Add project</span>
  </SidebarGroupAction>
  <SidebarGroupContent />
</SidebarGroup>

Collapsible groups pair with Collapsible. SidebarGroupLabel is a plain label slot—keep the trigger beside it (or fold the pattern into SidebarMenu like the preview at the top of this page):

<Collapsible className="group/collapsible" defaultOpen>
  <SidebarGroup>
    <div className="flex items-center gap-2 px-2">
      <SidebarGroupLabel className="flex-1 px-0">Help</SidebarGroupLabel>
      <CollapsibleTrigger
        className="rounded-md p-1.5 outline-none ring-sidebar-ring focus-visible:ring-2"
        type="button"
      >
        <ChevronDown className="size-4 transition-transform group-data-[state=open]/collapsible:rotate-180" />
      </CollapsibleTrigger>
    </div>
    <CollapsibleContent>
      <SidebarGroupContent />
    </CollapsibleContent>
  </SidebarGroup>
</Collapsible>

SidebarMenu

Row list inside a group—map data to SidebarMenuItem / SidebarMenuButton.

<SidebarMenu>
  {projects.map((project) => (
    <SidebarMenuItem key={project.name}>
      <SidebarMenuButton asChild>
        <a href={project.url}>
          <project.icon />
          <span>{project.name}</span>
        </a>
      </SidebarMenuButton>
    </SidebarMenuItem>
  ))}
</SidebarMenu>

SidebarMenuButton

Default renders a Button; use asChild for links. isActive highlights the active route; tooltip surfaces collapsed labels.

<SidebarMenuButton asChild isActive>
  <a href="#">Home</a>
</SidebarMenuButton>

SidebarMenuAction

Icon-only or compact action aligned to a row. Use showOnHover to reveal on row hover.

<SidebarMenuItem>
  <SidebarMenuButton asChild>
    <a href="#">
      <Home />
      <span>Home</span>
    </a>
  </SidebarMenuButton>
  <SidebarMenuAction>
    <Plus /> <span className="sr-only">Add project</span>
  </SidebarMenuAction>
</SidebarMenuItem>

SidebarMenuSub

Nested list hanging off a parent item.

<SidebarMenuItem>
  <SidebarMenuButton />
  <SidebarMenuSub>
    <SidebarMenuSubItem>
      <SidebarMenuSubButton href="#">Child</SidebarMenuSubButton>
    </SidebarMenuSubItem>
  </SidebarMenuSub>
</SidebarMenuItem>

SidebarMenuBadge

Small count or pill beside a row.

<SidebarMenuItem>
  <SidebarMenuButton />
  <SidebarMenuBadge>24</SidebarMenuBadge>
</SidebarMenuItem>

SidebarMenuSkeleton

Placeholder rows while async routes or prefs load.

<SidebarMenu>
  {Array.from({ length: 5 }).map((_, index) => (
    <SidebarMenuItem key={index}>
      <SidebarMenuSkeleton />
    </SidebarMenuItem>
  ))}
</SidebarMenu>

SidebarTrigger

Prebuilt toggle wired to context—drop next to your page title or in a toolbar.

import { useSidebar } from "@/components/ui/sidebar";

export function CustomTrigger() {
  const { toggleSidebar } = useSidebar();
  return <button type="button" onClick={toggleSidebar}>Toggle</button>;
}

Prefer SidebarTrigger when you want the default styling and accessibility bundle.

SidebarRail

Draggable edge control that expands or collapses the desktop rail—place after header/content/footer inside Sidebar.

<Sidebar>
  <SidebarHeader />
  <SidebarContent>
    <SidebarGroup />
  </SidebarContent>
  <SidebarFooter />
  <SidebarRail />
</Sidebar>