Sidebar

A composable, collapsible navigation panel for app-level layouts. Built on SidebarProvider context — manages open/closed state, a mobile-responsive Sheet fallback, and a ⌘B keyboard shortcut out of the box.

Anatomy

Wrap the entire layout in SidebarProvider, then place Sidebar and SidebarInset as siblings inside it. SidebarHeader and SidebarFooter are sticky; SidebarContent is the scrollable region.

Acme Inc
Navigation

Main content

SidebarProvider → Sidebar + SidebarInsetSidebarHeader (sticky top)SidebarContent (scrollable)SidebarFooter (sticky bottom)

Navigation Structure

Use SidebarGroup to section content, SidebarMenu / SidebarMenuItem for list structure, and SidebarMenuButton for the interactive element. Compose SidebarMenuBadge and SidebarMenuAction as siblings of the button inside the same SidebarMenuItem.

Acme Inc
Platform
  • 5
Account

Dashboard

SidebarGroupLabel + SidebarGroupAction (top-right)SidebarMenuBadge (Inbox count)SidebarMenuAction showOnHover (Projects)SidebarSeparator between groupssize="lg" user row in footer

Loading State

Render SidebarMenuSkeleton while async nav data loads. The showIcon prop adds an icon placeholder. Each skeleton item randomizes its width to reduce perceived layout shift.

Loading…

Collapsible Modes

The collapsible prop controls how the sidebar collapses. Pair it with SidebarTrigger in the page header — it is also bound to ⌘B / Ctrl+B automatically.

collapsible="offcanvas"

Slides fully off-screen. Best default — hides on both mobile and desktop.

collapsible="icon"

Collapses to icon-only width. Labels hide; tooltips appear on hover.

collapsible="none"

Always visible. Use for fixed layouts where the sidebar should never collapse.

Variants

The variant prop controls the visual treatment of the sidebar panel.

variant="sidebar"

Default. Flush with the edge, separated by a border.

variant="floating"

Floating panel with a box-shadow ring and rounded corners.

variant="inset"

Main content becomes inset with rounded corners and a shadow.

Design Guidelines

Do

  • Wrap the root layout. Place SidebarProvider in app/layout.tsx so open state persists across navigations.
  • Use icon mode for dense UIs. collapsible="icon" with tooltip props keeps navigation accessible while reclaiming screen space.
  • Place SidebarTrigger in every page header. Users expect a collapse toggle at the top-left of every page, alongside breadcrumbs.

Don't

  • Don't skip SidebarProvider. All sub-components consume sidebar context — rendering any of them outside the provider throws a runtime error.
  • Don't mount it inside a route segment. Placing SidebarProvider in a page component resets state on every navigation. Use the shared layout instead.
  • Don't hardcode the sidebar width. Adjust via the --sidebar-widthCSS variable in the provider's style prop — not in class names.

Developer Reference

useSidebar hook

  • state "expanded" | "collapsed"
  • open / setOpen — desktop boolean state
  • openMobile / setOpenMobile — mobile sheet state
  • isMobile— true when viewport < 768px
  • toggleSidebar() — toggle for current breakpoint

Accessibility

  • State exposed via data-state and data-collapsible — target these for CSS transitions.
  • Mobile renders a Sheet (role="dialog") with focus trapping and ESC dismissal.
  • SidebarRail provides a click/drag resize handle; add it as a child of Sidebar.
  • Keyboard shortcut: ⌘B / Ctrl+B — registered automatically by SidebarProvider.

Usage

// app/layout.tsx — wrap the root layout
import {
    SidebarProvider, Sidebar, SidebarHeader, SidebarContent,
    SidebarFooter, SidebarGroup, SidebarGroupLabel, SidebarGroupContent,
    SidebarGroupAction, SidebarMenu, SidebarMenuItem, SidebarMenuButton,
    SidebarMenuBadge, SidebarMenuAction, SidebarInset, SidebarTrigger,
    SidebarRail,
} from "@/components/ui/sidebar"
import Link from "next/link"
import { LayoutDashboard, FolderOpen, MoreHorizontal, Plus } from "lucide-react"

export default function RootLayout({ children }: { children: React.ReactNode }) {
    return (
        <SidebarProvider>
            <Sidebar collapsible="icon">
                <SidebarHeader>
                    <SidebarMenu>
                        <SidebarMenuItem>
                            <SidebarMenuButton size="lg" render={<Link href="/" />}>
                                <AppLogo />
                                <span>Acme Inc</span>
                            </SidebarMenuButton>
                        </SidebarMenuItem>
                    </SidebarMenu>
                </SidebarHeader>

                <SidebarContent>
                    <SidebarGroup>
                        <SidebarGroupLabel>Platform</SidebarGroupLabel>
                        <SidebarGroupAction title="New project">
                            <Plus />
                        </SidebarGroupAction>
                        <SidebarGroupContent>
                            <SidebarMenu>
                                <SidebarMenuItem>
                                    <SidebarMenuButton
                                        isActive
                                        tooltip="Dashboard"
                                        render={<Link href="/dashboard" />}
                                    >
                                        <LayoutDashboard />
                                        <span>Dashboard</span>
                                    </SidebarMenuButton>
                                    <SidebarMenuBadge>3</SidebarMenuBadge>
                                </SidebarMenuItem>
                                <SidebarMenuItem>
                                    <SidebarMenuButton
                                        tooltip="Projects"
                                        render={<Link href="/projects" />}
                                    >
                                        <FolderOpen />
                                        <span>Projects</span>
                                    </SidebarMenuButton>
                                    <SidebarMenuAction showOnHover title="More options">
                                        <MoreHorizontal />
                                    </SidebarMenuAction>
                                </SidebarMenuItem>
                            </SidebarMenu>
                        </SidebarGroupContent>
                    </SidebarGroup>
                </SidebarContent>

                <SidebarFooter>
                    <SidebarMenu>
                        <SidebarMenuItem>
                            <SidebarMenuButton size="lg">
                                <UserAvatar />
                                <div className="flex flex-col text-left leading-none">
                                    <span className="font-semibold">John Doe</span>
                                    <span className="truncate text-xs opacity-70">john@acme.com</span>
                                </div>
                            </SidebarMenuButton>
                        </SidebarMenuItem>
                    </SidebarMenu>
                </SidebarFooter>

                <SidebarRail />
            </Sidebar>

            <SidebarInset>
                <header className="flex h-14 items-center gap-4 border-b px-6">
                    <SidebarTrigger />
                    {/* breadcrumbs */}
                </header>
                {children}
            </SidebarInset>
        </SidebarProvider>
    )
}