Sidebar
Navegação lateral completa com grupos, ações e estado colapsável persistente
Sidebar é o esqueleto da navegação principal em aplicações Uranus. Ele coordena provider, conteúdo rolável, grupos de menu, rodapé, trigger e um SidebarInset para a área de conteúdo — tudo com estado colapsável persistente via cookie e atalho de teclado.
'use client';
import {
Sidebar,
SidebarContent,
SidebarFooter,
SidebarGroup,
SidebarGroupContent,
SidebarGroupLabel,
SidebarHeader,
SidebarInset,
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
SidebarProvider,
SidebarTrigger,
} from '@uranus-workspace/design-system';
import {
BarChart3,
FolderKanban,
LayoutDashboard,
LifeBuoy,
LogOut,
Rocket,
Settings,
Users,
} from 'lucide-react';
const workspace = [
{ title: 'Dashboard', icon: LayoutDashboard, isActive: true },
{ title: 'Projetos', icon: FolderKanban },
{ title: 'Equipe', icon: Users },
{ title: 'Relatórios', icon: BarChart3 },
];
const account = [
{ title: 'Configurações', icon: Settings },
{ title: 'Suporte', icon: LifeBuoy },
];
export default function SidebarDefault() {
return (
<div className="h-[460px] w-[760px] overflow-hidden rounded-lg border">
<SidebarProvider className="min-h-full">
<Sidebar collapsible="none" className="border-r">
<SidebarHeader>
<div className="flex items-center gap-2 px-2 py-1.5">
<div className="flex size-8 items-center justify-center rounded-md bg-primary text-primary-foreground">
<Rocket className="size-4" />
</div>
<div className="flex flex-col">
<span className="text-sm font-semibold">Uranus</span>
<span className="text-xs text-muted-foreground">Workspace pessoal</span>
</div>
</div>
</SidebarHeader>
<SidebarContent>
<SidebarGroup>
<SidebarGroupLabel>Workspace</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>
{workspace.map((item) => (
<SidebarMenuItem key={item.title}>
<SidebarMenuButton isActive={item.isActive}>
<item.icon />
<span>{item.title}</span>
</SidebarMenuButton>
</SidebarMenuItem>
))}
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
<SidebarGroup>
<SidebarGroupLabel>Conta</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>
{account.map((item) => (
<SidebarMenuItem key={item.title}>
<SidebarMenuButton>
<item.icon />
<span>{item.title}</span>
</SidebarMenuButton>
</SidebarMenuItem>
))}
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
</SidebarContent>
<SidebarFooter>
<SidebarMenu>
<SidebarMenuItem>
<SidebarMenuButton>
<LogOut />
<span>Sair</span>
</SidebarMenuButton>
</SidebarMenuItem>
</SidebarMenu>
</SidebarFooter>
</Sidebar>
<SidebarInset>
<header className="flex h-14 items-center gap-2 border-b px-4">
<SidebarTrigger />
<span className="text-sm font-medium">Dashboard</span>
</header>
<div className="flex flex-1 items-center justify-center p-6 text-sm text-muted-foreground">
Área principal do produto
</div>
</SidebarInset>
</SidebarProvider>
</div>
);
}
Anatomia
- SidebarProvider — raiz obrigatória. Guarda o estado
open/collapsed, persiste em cookie (sidebar_state) e registra o atalhoCmd/Ctrl + B. - Sidebar — o contêiner lateral. Aceita
side="left" | "right",variant="sidebar" | "floating" | "inset"ecollapsible="offcanvas" | "icon" | "none". - SidebarHeader / SidebarFooter — regiões fixas no topo e rodapé.
- SidebarContent — área rolável do meio.
- SidebarGroup + SidebarGroupLabel + SidebarGroupContent — agrupam itens relacionados sob um título.
- SidebarMenu → SidebarMenuItem → SidebarMenuButton — a lista navegável. O botão aceita
isActive,tooltip(mostrado quando a sidebar está em modo icon) easChildpara integrar comnext/link. - SidebarMenuSub / SidebarMenuSubItem / SidebarMenuSubButton — submenus aninhados.
- SidebarTrigger — botão que alterna aberto/fechado. Tipicamente vai no header do
SidebarInset. - SidebarInset —
<main>que encapsula o conteúdo da página ao lado da sidebar. No modovariant="inset"ganha cantos arredondados e sombra. - SidebarRail — faixa invisível na borda para redimensionar/colapsar por hover.
- SidebarInput / SidebarSeparator / SidebarMenuBadge / SidebarMenuAction / SidebarMenuSkeleton — utilitários para busca, separação, contadores, ações inline e estados de loading.
- useSidebar() — hook que expõe
open,setOpen,toggleSidebar,stateeisMobile.
Uso mínimo
'use client';
import {
Sidebar,
SidebarContent,
SidebarGroup,
SidebarGroupContent,
SidebarGroupLabel,
SidebarInset,
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
SidebarProvider,
SidebarTrigger,
} from '@uranus-workspace/design-system';
export function AppShell({ children }: { children: React.ReactNode }) {
return (
<SidebarProvider>
<Sidebar>
<SidebarContent>
<SidebarGroup>
<SidebarGroupLabel>Workspace</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>
<SidebarMenuItem>
<SidebarMenuButton isActive>Dashboard</SidebarMenuButton>
</SidebarMenuItem>
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
</SidebarContent>
</Sidebar>
<SidebarInset>
<header className="flex h-14 items-center gap-2 border-b px-4">
<SidebarTrigger />
</header>
{children}
</SidebarInset>
</SidebarProvider>
);
}Modos de colapso
collapsible="offcanvas"(padrão) — a sidebar desliza para fora da tela no estado recolhido. Ideal para desktop.collapsible="icon"— permanece visível como uma faixa estreita com ícones. Use quando o produto precisa de acesso rápido mesmo com a sidebar "recolhida". Combine com a proptooltipemSidebarMenuButton.collapsible="none"— desativa o toggle. Útil para o embutido da documentação e para testes.
No mobile, o componente automaticamente substitui o layout por um Sheet lateral — o mesmo código funciona em ambas as larguras.
Faça
- Coloque o
SidebarTriggerdentro do header doSidebarInset, próximo ao título da página. - Agrupe itens com
SidebarGroup+SidebarGroupLabelpara criar hierarquia legível. - Use
SidebarMenuButton asChildcomnext/linkpara navegação real. - Marque exatamente um item como
isActivepor rota.
Não faça
- Não use
Sidebarsem envolver a aplicação comSidebarProvider— o hookuseSidebar()vai lançar. - Não coloque ações destrutivas soltas no
SidebarFooter. Agrupe dentro de um menu com confirmação. - Não repita a mesma navegação em
Sidebare numanavigation-menuno topo. Escolha um.
Acessibilidade
- A
Sidebaré renderizada dentro de um wrapper<nav>semântico automaticamente e cadaSidebarMenuButtoné um<button>focável. - Atalho de teclado global:
Cmd+B(macOS) ouCtrl+B(Windows/Linux) alterna a sidebar. - No modo icon, o
tooltipé anunciado quando o botão recebe foco pelo teclado — via Radix Tooltip. - No mobile o
Sheetaplica focus trap eEscfecha.