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