Skip to Content
ComponentsAtomsSheet

Sheet

Atom / overlay primitive

Sheet é um painel lateral. Ele preserva contexto; não interrompe como um Dialog.

Use Sheet quando a tarefa precisa de uma camada conectada à página: drill-down de menção, filtros avançados, configuração contextual ou edição curta. Para fluxos responsivos, prefira Responsive Sheet.

Exemplos copiáveis

React

import * as React from "react" type PulsoSheetProps = { open: boolean title: string description?: string side?: "left" | "right" children: React.ReactNode footer?: React.ReactNode onOpenChange: (open: boolean) => void } export function PulsoSheet({ open, title, description, side = "right", children, footer, onOpenChange }: PulsoSheetProps) { const titleId = React.useId() const descriptionId = description ? `${titleId}-description` : undefined React.useEffect(() => { if (!open) return function onKeyDown(event: KeyboardEvent) { if (event.key === "Escape") onOpenChange(false) } document.addEventListener("keydown", onKeyDown) return () => document.removeEventListener("keydown", onKeyDown) }, [onOpenChange, open]) if (!open) return null return ( <div className="fixed inset-0 z-50"> <button type="button" aria-label="Fechar painel" className="absolute inset-0 h-full w-full cursor-default bg-black/30" onClick={() => onOpenChange(false)} /> <aside role="dialog" aria-modal="true" aria-labelledby={titleId} aria-describedby={descriptionId} className={[ "absolute top-0 h-full w-[min(480px,calc(100vw-3rem))] border border-[var(--border)] bg-[var(--popover)] shadow-[var(--shadow-lg)]", side === "right" ? "right-0 rounded-l-[var(--radius-xl)]" : "left-0 rounded-r-[var(--radius-xl)]", ].join(" ")}> <header className="flex items-start justify-between gap-4 border-b border-[var(--border)] p-5"> <div> <h2 id={titleId} className="text-lg font-semibold text-[var(--fg)]">{title}</h2> {description ? <p id={descriptionId} className="mt-1 text-sm leading-6 text-[var(--fg-muted)]">{description}</p> : null} </div> <button type="button" aria-label="Fechar" onClick={() => onOpenChange(false)} className="rounded-[var(--radius-sm)] px-2 py-1 text-[var(--fg-muted)] hover:bg-[var(--muted)] hover:text-[var(--fg)]">×</button> </header> <div className="h-[calc(100dvh-9rem)] overflow-y-auto p-5 text-sm text-[var(--fg)]">{children}</div> {footer ? <footer className="border-t border-[var(--border)] p-4">{footer}</footer> : null} </aside> </div> ) }
<PulsoSheet open={open} onOpenChange={setOpen} title="Fontes do caso" description="Revise evidências sem perder a lista de origem."> <p>Relatório reputacional · validado há 2 min</p> </PulsoSheet>

Quando usar

  • Drill-down de item mantendo a lista como contexto.
  • Filtros avançados acionados por Filter Bar.
  • Configuração lateral que não exige página própria.
  • Formulários curtos que dependem do contexto de origem.

Quando não usar

  • Para confirmação crítica; use Dialog/Alert Dialog.
  • Para conteúdo exploratório muito longo; use página dedicada.
  • Para mobile sem adaptação; use Responsive Sheet.
  • Para esconder ação destrutiva sem confirmação.

Regras

  1. Conteúdo longo rola dentro do Sheet, não a página por trás.
  2. Filtros ativos no Sheet precisam aparecer fora dele também.
  3. Não abra Sheet sobre Sheet sem decisão explícita.
  4. Ações destrutivas dentro do Sheet exigem confirmação proporcional.
  5. Conteúdo assistido por IA mostra origem, confiança e base.
Last updated on