Sidebar
Core Idea
A composable, themeable, customizable sidebar system. Use as the standard app-shell navigation pattern (collapsible left/right panel with header, scrollable content, footer, and a rail) instead of hand-rolling layout CSS.
Key Concepts
SidebarProvider: root context provider handling open/collapsed state and mobile detection; must always wrap the app. Props: defaultOpen, open + onOpenChange (controlled).
Sidebar: the main panel. Props: side (left/right), variant (sidebar/floating/inset), collapsible (offcanvas/icon/none).
SidebarInset: required wrapper for main content when Sidebar uses variant="inset".
useSidebar(): hook exposing state (expanded/collapsed), open, setOpen, openMobile, setOpenMobile, isMobile, toggleSidebar.
- Width via CSS vars: single sidebar → edit
SIDEBAR_WIDTH/SIDEBAR_WIDTH_MOBILE constants in sidebar.tsx; multiple sidebars → pass --sidebar-width/--sidebar-width-mobile in the style prop of SidebarProvider.
- Keyboard shortcut:
cmd+b (Mac) / ctrl+b (Windows) toggles the sidebar by default, defined by SIDEBAR_KEYBOARD_SHORTCUT = "b" in sidebar.tsx.
SidebarMenuButton: renders a button by default; use render prop to swap for <a>/Link; isActive prop marks it as the active item.
- Collapsible groups/menus: nest
SidebarGroup/SidebarMenuItem inside a Collapsible (from @/components/ui/collapsible), wiring SidebarGroupLabel/SidebarMenuButton with render={<CollapsibleTrigger />}.
group-data-[collapsible=icon]:hidden: Tailwind data-attribute pattern to hide elements (e.g. a SidebarGroup) only when the sidebar is collapsed to icon mode.
dir prop: Sidebar accepts dir="rtl" for right-to-left layouts; requires the component's internal RTL wiring (see Anti-patterns).
Code Examples
import { SidebarProvider, SidebarTrigger } from "@/components/ui/sidebar"
import { AppSidebar } from "@/components/app-sidebar"
export default function Layout({ children }: { children: React.ReactNode }) {
return (
<SidebarProvider>
<AppSidebar />
<main>
<SidebarTrigger />
{children}
</main>
</SidebarProvider>
)
}
- O que demonstra: setup mínimo obrigatório no layout raiz.
import {
Sidebar,
SidebarContent,
SidebarFooter,
SidebarGroup,
SidebarHeader,
} from "@/components/ui/sidebar"
export function AppSidebar() {
return (
<Sidebar>
<SidebarHeader />
<SidebarContent>
<SidebarGroup />
<SidebarGroup />
</SidebarContent>
<SidebarFooter />
</Sidebar>
)
}
- O que demonstra: esqueleto estrutural do sidebar da aplicação.
<SidebarProvider>
<Sidebar variant="inset" />
<SidebarInset>
<main>{children}</main>
</SidebarInset>
</SidebarProvider>
- O que demonstra: variante
inset exige envolver o conteúdo principal em SidebarInset.
<Collapsible defaultOpen className="group/collapsible">
<SidebarGroup>
<SidebarGroupLabel render={<CollapsibleTrigger />}>
Help
<ChevronDown className="ml-auto transition-transform group-data-open/collapsible:rotate-180" />
</SidebarGroupLabel>
<CollapsibleContent>
<SidebarGroupContent />
</CollapsibleContent>
</SidebarGroup>
</Collapsible>
- O que demonstra: grupo de navegação colapsável usando
Collapsible + render no SidebarGroupLabel.
export function AppSidebar() {
const [open, setOpen] = React.useState(false)
return (
<SidebarProvider open={open} onOpenChange={setOpen}>
<Sidebar />
</SidebarProvider>
)
}
- O que demonstra: sidebar controlado externamente via
open/onOpenChange.
Composition
SidebarProvider
├── Sidebar
│ ├── SidebarHeader
│ ├── SidebarContent
│ │ ├── SidebarGroup
│ │ │ ├── SidebarGroupLabel
│ │ │ ├── SidebarGroupAction
│ │ │ ├── SidebarGroupContent
│ │ │ └── SidebarMenu
│ │ │ ├── SidebarMenuItem
│ │ │ │ ├── SidebarMenuButton
│ │ │ │ ├── SidebarMenuAction
│ │ │ │ └── SidebarMenuBadge
│ │ │ └── SidebarMenuItem
│ │ │ ├── SidebarMenuButton
│ │ │ └── SidebarMenuSub
│ │ │ ├── SidebarMenuSubItem
│ │ │ └── SidebarMenuSubItem
│ │ └── SidebarGroup
│ ├── SidebarFooter
│ └── SidebarRail
├── SidebarInset
└── SidebarTrigger
Reference Tables
SidebarProvider props
| Name | Type | Description |
|---|
defaultOpen | boolean | Default open state. |
open | boolean | Open state (controlled). |
onOpenChange | (open: boolean) => void | Sets open state (controlled). |
Sidebar props
| Property | Type | Description |
|---|
side | left | right | Which side the sidebar renders on. |
variant | sidebar | floating | inset | Visual variant. inset requires SidebarInset around main content. |
collapsible | offcanvas | icon | none | offcanvas slides in/out; icon collapses to icon rail; none is non-collapsible. |
useSidebar() return
| Property | Type | Description |
|---|
state | expanded | collapsed | Current sidebar state. |
open / setOpen | boolean / setter | Desktop open state. |
openMobile / setOpenMobile | boolean / setter | Mobile open state. |
isMobile | boolean | Whether running in mobile view. |
toggleSidebar | () => void | Toggles sidebar on both desktop and mobile. |
Anti-patterns
- Usar
variant="inset" sem SidebarInset: quebra o layout, SidebarInset é obrigatório para essa variante.
- Aplicar RTL só passando
dir="rtl" numa versão antiga do componente: versões anteriores do Sidebar precisam de patch manual (propagar dir ao SheetContent mobile, adicionar data-side, trocar classes de posicionamento por seletores data-[side=...], e className="rtl:rotate-180" no ícone do SidebarTrigger) antes que dir funcione corretamente.
- Esconder
SidebarGroup manualmente com JS condicional no modo ícone: usar a classe group-data-[collapsible=icon]:hidden, não lógica de renderização condicional.
Key Takeaways
SidebarProvider é obrigatório e único ponto de estado (open/collapsed/mobile) para toda a árvore de sidebar.
collapsible="icon" + classes group-data-[collapsible=icon]:* é o padrão para esconder/ajustar conteúdo quando colapsado, sem lógica JS extra.
- Largura é controlada por CSS vars (
--sidebar-width), não por prop numérica direta.
- Grupos e itens de menu colapsáveis reutilizam o componente
Collapsible genérico via render prop, não uma prop collapsible embutida em SidebarMenuItem.
- Tema usa variáveis CSS próprias (
--sidebar-background, --sidebar-primary, etc.), separadas das variáveis de tema geral do shadcn.
- Atalho de teclado padrão é
cmd/ctrl+b, configurável editando a constante SIDEBAR_KEYBOARD_SHORTCUT no arquivo fonte.
Connects To
- Collapsible: primitivo usado internamente para grupos/itens de menu expansíveis dentro do sidebar.
- DropdownMenu: padrão comum para team switcher e menu de usuário no
SidebarHeader/SidebarFooter.
- Breadcrumb: tipicamente usado junto no header do conteúdo principal ao lado de
SidebarTrigger.
- Sheet: usado internamente pelo
Sidebar para a versão mobile (off-canvas).