Uranus® Design System
Blocos

AppSidebar

Navegação lateral opinada para dashboards — marca, busca, grupos e footer no padrão sidebar-01 (shadcn).

AppSidebar compõe o primitivo Sidebar do @uranus-workspace/design-system com componentes nomeados:

  • AppSidebar.Header — topo do trilho (marca, workspace switcher).
  • AppSidebar.Brand — linha de produto: Brand.Icon, Brand.Body (Brand.Title, Brand.Subtitle), Brand.Action (densidade sidebar-01).
  • AppSidebar.Search — campo com ícone (SidebarInput + token).
  • AppSidebar.Content — área rolável; dentro dela use SidebarGroup, SidebarGroupLabel, SidebarMenu e AppSidebar.NavLink (do @uranus-workspace/design-system).
  • AppSidebar.Footer — rodapé (usuário, versão).
  • AppSidebar.NavLink — links com BlockLink, aria-current e tooltip no modo ícone.

Monte a árvore com children — não há menu serializado por props.

Em docs ou iframe estreito, o Sidebar padrão é fixo na viewport — use collapsible="none" no preview para o trilho ficar no fluxo (como no exemplo abaixo). Em apps reais deixe o collapsible padrão.

O preview usa align="stretch" e altura mínima maior para o exemplo ocupar toda a largura útil (sidebar + área principal lado a lado), sem ficar comprimido ao centro.

Documentationv1.0.1
Useryou@uranus.com.br
'use client';
import { AppHeader, AppSidebar } from '@uranus-workspace/blocks';
import {
  BreadcrumbItem,
  BreadcrumbLink,
  BreadcrumbList,
  BreadcrumbPage,
  BreadcrumbSeparator,
  Button,
  Separator,
  SidebarGroup,
  SidebarGroupContent,
  SidebarGroupLabel,
  SidebarInset,
  SidebarMenu,
  SidebarProvider,
  SidebarTrigger,
} from '@uranus-workspace/design-system';
import {
  BookOpen,
  ChevronsUpDown,
  Code,
  FileCode,
  FileText,
  FolderTree,
  Layers,
  Rocket,
} from 'lucide-react';

export default function AppSidebarDefault() {
  return (
    <div className="box-border flex h-[min(680px,78vh)] min-h-[520px] w-full min-w-0 flex-col overflow-hidden rounded-xl border border-fd-border bg-fd-background shadow-sm">
      <SidebarProvider className="flex min-h-0 w-full flex-1 flex-col">
        <div className="flex min-h-0 min-w-0 w-full flex-1 flex-row">
          <AppSidebar
            collapsible="none"
            className="w-[min(100%,19rem)] shrink-0 border-r border-sidebar-border"
          >
            <AppSidebar.Header>
              <AppSidebar.Brand>
                <AppSidebar.Brand.Icon>
                  <BookOpen aria-hidden />
                </AppSidebar.Brand.Icon>
                <AppSidebar.Brand.Body>
                  <AppSidebar.Brand.Title>Documentation</AppSidebar.Brand.Title>
                  <AppSidebar.Brand.Subtitle>v1.0.1</AppSidebar.Brand.Subtitle>
                </AppSidebar.Brand.Body>
                <AppSidebar.Brand.Action>
                  <Button
                    type="button"
                    variant="ghost"
                    size="icon"
                    className="size-8 shrink-0"
                    aria-label="Switch workspace"
                  >
                    <ChevronsUpDown aria-hidden className="size-4 opacity-70" />
                  </Button>
                </AppSidebar.Brand.Action>
              </AppSidebar.Brand>
            </AppSidebar.Header>
            <AppSidebar.Content>
              <AppSidebar.Search placeholder="Search the docs…" />
              <SidebarGroup>
                <SidebarGroupLabel>Getting started</SidebarGroupLabel>
                <SidebarGroupContent>
                  <SidebarMenu>
                    <AppSidebar.NavLink
                      href="#installation"
                      icon={<Rocket aria-hidden className="size-4" />}
                      label="Installation"
                    >
                      Installation
                    </AppSidebar.NavLink>
                    <AppSidebar.NavLink
                      href="#structure"
                      icon={<FolderTree aria-hidden className="size-4" />}
                      label="Project structure"
                    >
                      Project structure
                    </AppSidebar.NavLink>
                  </SidebarMenu>
                </SidebarGroupContent>
              </SidebarGroup>
              <SidebarGroup>
                <SidebarGroupLabel>Build your application</SidebarGroupLabel>
                <SidebarGroupContent>
                  <SidebarMenu>
                    <AppSidebar.NavLink
                      href="#routing"
                      icon={<Layers aria-hidden className="size-4" />}
                      label="Routing"
                    >
                      Routing
                    </AppSidebar.NavLink>
                    <AppSidebar.NavLink
                      href="#data"
                      icon={<Code aria-hidden className="size-4" />}
                      active
                      label="Data fetching"
                    >
                      Data fetching
                    </AppSidebar.NavLink>
                    <AppSidebar.NavLink
                      href="#rendering"
                      icon={<FileCode aria-hidden className="size-4" />}
                      label="Rendering"
                    >
                      Rendering
                    </AppSidebar.NavLink>
                    <AppSidebar.NavLink
                      href="#middleware"
                      icon={<FileText aria-hidden className="size-4" />}
                      label="Middleware"
                    >
                      Middleware
                    </AppSidebar.NavLink>
                  </SidebarMenu>
                </SidebarGroupContent>
              </SidebarGroup>
            </AppSidebar.Content>
            <AppSidebar.Footer>
              <div className="flex items-center gap-2 border-t border-sidebar-border px-2 py-3">
                <div
                  className="flex size-8 shrink-0 items-center justify-center rounded-lg bg-sidebar-accent text-xs font-medium text-sidebar-accent-foreground"
                  aria-hidden
                >
                  UT
                </div>
                <div className="grid min-w-0 flex-1 gap-0.5 text-left text-xs leading-tight">
                  <span className="truncate font-medium text-sidebar-foreground">User</span>
                  <span className="truncate text-sidebar-foreground/70">you@uranus.com.br</span>
                </div>
                <ChevronsUpDown aria-hidden className="size-4 shrink-0 opacity-50" />
              </div>
            </AppSidebar.Footer>
          </AppSidebar>
          <SidebarInset className="min-h-0 flex min-w-0 flex-1 flex-col overflow-hidden bg-background">
            <AppHeader>
              <SidebarTrigger className="-ml-1" />
              <Separator orientation="vertical" className="mr-1 data-[orientation=vertical]:h-4" />
              <AppHeader.Breadcrumbs>
                <BreadcrumbList className="text-sm">
                  <BreadcrumbItem className="hidden sm:inline-flex">
                    <BreadcrumbLink href="#">Build your application</BreadcrumbLink>
                  </BreadcrumbItem>
                  <BreadcrumbSeparator className="hidden sm:inline-flex" />
                  <BreadcrumbItem>
                    <BreadcrumbPage>Data fetching</BreadcrumbPage>
                  </BreadcrumbItem>
                </BreadcrumbList>
              </AppHeader.Breadcrumbs>
            </AppHeader>
            <div className="flex flex-1 flex-col gap-4 overflow-auto p-4">
              <div className="grid auto-rows-min gap-4 md:grid-cols-3">
                <div className="aspect-video rounded-xl bg-muted/60" />
                <div className="aspect-video rounded-xl bg-muted/60" />
                <div className="aspect-video rounded-xl bg-muted/60" />
              </div>
              <div className="min-h-40 flex-1 rounded-xl bg-muted/60 md:min-h-min" />
            </div>
          </SidebarInset>
        </div>
      </SidebarProvider>
    </div>
  );
}

Uso

import { AppSidebar } from '@uranus-workspace/blocks';
import {
  Button,
  SidebarGroup,
  SidebarGroupContent,
  SidebarGroupLabel,
  SidebarMenu,
} from '@uranus-workspace/design-system';
import { BookOpen, ChevronsUpDown, Home } from 'lucide-react';

<AppSidebar collapsible="none">
  <AppSidebar.Header>
    <AppSidebar.Brand>
      <AppSidebar.Brand.Icon>
        <BookOpen aria-hidden />
      </AppSidebar.Brand.Icon>
      <AppSidebar.Brand.Body>
        <AppSidebar.Brand.Title>Documentation</AppSidebar.Brand.Title>
        <AppSidebar.Brand.Subtitle>v1.0.1</AppSidebar.Brand.Subtitle>
      </AppSidebar.Brand.Body>
      <AppSidebar.Brand.Action>
        <Button type="button" variant="ghost" size="icon" aria-label="Workspace">
          <ChevronsUpDown aria-hidden className="size-4" />
        </Button>
      </AppSidebar.Brand.Action>
    </AppSidebar.Brand>
  </AppSidebar.Header>
  <AppSidebar.Content>
    <AppSidebar.Search placeholder="Search the docs…" />
    <SidebarGroup>
      <SidebarGroupLabel>Getting started</SidebarGroupLabel>
      <SidebarGroupContent>
        <SidebarMenu>
          <AppSidebar.NavLink href="/docs/install" icon={<Home aria-hidden className="size-4" />} label="Installation">
            Installation
          </AppSidebar.NavLink>
        </SidebarMenu>
      </SidebarGroupContent>
    </SidebarGroup>
  </AppSidebar.Content>
</AppSidebar>

Roteamento

Os links resolvem o componente de âncora via BlockLink na seguinte ordem:

  1. Prop linkComponent no AppSidebar.
  2. LinkProvider no topo da árvore.
  3. Elemento nativo <a>.
import Link from 'next/link';
import { AppSidebar, LinkProvider } from '@uranus-workspace/blocks';
import { SidebarGroup, SidebarGroupContent, SidebarGroupLabel, SidebarMenu } from '@uranus-workspace/design-system';

<LinkProvider linkComponent={Link}>
  <AppSidebar>
    <AppSidebar.Content>
      <SidebarGroup>
        <SidebarGroupLabel>Conta</SidebarGroupLabel>
        <SidebarGroupContent>
          <SidebarMenu>
            <AppSidebar.NavLink href="/settings">Configurações</AppSidebar.NavLink>
          </SidebarMenu>
        </SidebarGroupContent>
      </SidebarGroup>
    </AppSidebar.Content>
  </AppSidebar>
</LinkProvider>

Diretrizes

  • Use ícones decorativos (aria-hidden) — o label carrega o peso semântico.
  • active em AppSidebar.NavLink é responsabilidade do consumidor (geralmente derivado de usePathname()).
  • Para densidade próxima ao bloco oficial: grupo com label em sentence case, ícones size-4, busca logo abaixo do header.