Sheet
Painel lateral que desliza a partir da borda da viewport para acomodar fluxos secundários
Sheet é um painel modal que desliza a partir de uma borda da tela. Use-o quando o fluxo principal precisa continuar visível por contexto, mas a tarefa atual é longa demais para um Popover — edição de perfil, filtros de uma lista, navegação lateral em telas estreitas. Para um painel que sobe a partir do rodapé em mobile prefira Drawer.
'use client';
import {
Button,
Input,
Label,
Sheet,
SheetClose,
SheetContent,
SheetDescription,
SheetFooter,
SheetHeader,
SheetTitle,
SheetTrigger,
} from '@uranus-workspace/design-system';
export default function SheetDefault() {
return (
<Sheet>
<SheetTrigger asChild>
<Button variant="outline">Editar perfil</Button>
</SheetTrigger>
<SheetContent>
<SheetHeader>
<SheetTitle>Editar perfil</SheetTitle>
<SheetDescription>
Atualize suas informações pessoais. As mudanças são aplicadas ao confirmar.
</SheetDescription>
</SheetHeader>
<div className="grid gap-4 py-6">
<div className="grid gap-2">
<Label htmlFor="sheet-name">Nome</Label>
<Input id="sheet-name" defaultValue="Gustavo Bertoi" />
</div>
<div className="grid gap-2">
<Label htmlFor="sheet-email">E-mail</Label>
<Input id="sheet-email" type="email" defaultValue="gustavo@uranus.com.br" />
</div>
</div>
<SheetFooter>
<SheetClose asChild>
<Button variant="outline">Cancelar</Button>
</SheetClose>
<Button>Salvar alterações</Button>
</SheetFooter>
</SheetContent>
</Sheet>
);
}
Anatomia
- SheetTrigger — elemento que abre o painel.
- SheetContent — o painel em si. Aceita a prop
side("top" | "right" | "bottom" | "left", padrão"right"). - SheetHeader → SheetTitle + SheetDescription — título e contexto.
- SheetFooter — área para ações principais.
- SheetClose — botão para fechar explicitamente. Um
Xno canto superior direito já é incluído por padrão.
Ancorado à esquerda
Use side="left" para navegação mobile ou árvores de conteúdo que normalmente ficam fixas à esquerda em telas maiores.
'use client';
import {
Button,
Sheet,
SheetContent,
SheetDescription,
SheetHeader,
SheetTitle,
SheetTrigger,
} from '@uranus-workspace/design-system';
import { Menu } from 'lucide-react';
export default function SheetLeft() {
return (
<Sheet>
<SheetTrigger asChild>
<Button variant="outline" size="icon" aria-label="Abrir menu">
<Menu />
</Button>
</SheetTrigger>
<SheetContent side="left">
<SheetHeader>
<SheetTitle>Navegação</SheetTitle>
<SheetDescription>Acesse rapidamente as principais áreas do produto.</SheetDescription>
</SheetHeader>
<nav className="mt-6 flex flex-col gap-1 text-sm">
<a className="rounded-md px-2 py-2 hover:bg-accent" href="#inicio">
Início
</a>
<a className="rounded-md px-2 py-2 hover:bg-accent" href="#projetos">
Projetos
</a>
<a className="rounded-md px-2 py-2 hover:bg-accent" href="#equipe">
Equipe
</a>
<a className="rounded-md px-2 py-2 hover:bg-accent" href="#configuracoes">
Configurações
</a>
</nav>
</SheetContent>
</Sheet>
);
}
Uso
import {
Button,
Sheet,
SheetContent,
SheetDescription,
SheetHeader,
SheetTitle,
SheetTrigger,
} from '@uranus-workspace/design-system';
<Sheet>
<SheetTrigger asChild>
<Button variant="outline">Abrir painel</Button>
</SheetTrigger>
<SheetContent side="right">
<SheetHeader>
<SheetTitle>Editar perfil</SheetTitle>
<SheetDescription>Atualize suas informações pessoais.</SheetDescription>
</SheetHeader>
</SheetContent>
</Sheet>Faça
- Use
side="right"para ações secundárias em desktop eside="left"para navegação. - Mantenha sempre um
SheetTitle, mesmo que visualmente escondido comclassName="sr-only"— leitores de tela precisam dele. - Posicione ações principais no
SheetFooterpara que não desçam junto ao conteúdo.
Não faça
- Não use
Sheetpara confirmações curtas — useAlertDialog. - Não aninhe sheets dentro de sheets.
- Não esconda o botão de fechar — ele é parte do contrato de acessibilidade.
Acessibilidade
- Construído sobre Radix Dialog — foco fica preso,
Escfecha e o fundo recebeinertenquanto o sheet está aberto. SheetTitleeSheetDescriptionsão associados viaaria-labelledbyearia-describedbyautomaticamente.- O botão de fechar padrão inclui um
spancomsr-onlygarantindo nome acessível. - Respeita
prefers-reduced-motion— o slide é substituído por um fade simples.