Dialog
Organism
Dialog interrompe o fluxo. Use só quando a tarefa exige atenção exclusiva ou decisão explícita.
Dialog é uma janela modal centralizada para confirmações, formulários curtos e revelações focadas. Diferente de Sheet, ele bloqueia o contexto por trás. Se a ação é destrutiva ou irreversível, use Alert Dialog.
Exemplos copiáveis
React
React
import * as React from "react"
type PulsoDialogProps = {
open: boolean
title: string
description: string
children: React.ReactNode
primaryAction: React.ReactNode
secondaryAction?: React.ReactNode
onOpenChange: (open: boolean) => void
}
export function PulsoDialog({ open, title, description, children, primaryAction, secondaryAction, onOpenChange }: PulsoDialogProps) {
const titleId = React.useId()
const descriptionId = React.useId()
const panelRef = React.useRef<HTMLDivElement>(null)
React.useEffect(() => {
if (!open) return
const previousActiveElement = document.activeElement as HTMLElement | null
function onKeyDown(event: KeyboardEvent) {
if (event.key === "Escape") onOpenChange(false)
}
document.addEventListener("keydown", onKeyDown)
panelRef.current?.focus()
return () => {
document.removeEventListener("keydown", onKeyDown)
previousActiveElement?.focus()
}
}, [onOpenChange, open])
if (!open) return null
return (
<div className="fixed inset-0 z-50 grid place-items-center bg-black/45 p-4">
<div ref={panelRef} role="dialog" aria-modal="true" aria-labelledby={titleId} aria-describedby={descriptionId} tabIndex={-1} className="w-full max-w-lg rounded-[var(--radius-lg)] border border-[var(--border)] bg-[var(--popover)] shadow-[var(--shadow-lg)] outline-none">
<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>
<p id={descriptionId} className="mt-1 text-sm leading-6 text-[var(--fg-muted)]">{description}</p>
</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)]">×</button>
</header>
<div className="p-5 text-sm text-[var(--fg)]">{children}</div>
<footer className="flex items-center justify-end gap-2 border-t border-[var(--border)] p-4">{secondaryAction}{primaryAction}</footer>
</div>
</div>
)
}<PulsoDialog
open={open}
onOpenChange={setOpen}
title="Confirmar despacho assistido"
description="Revise a recomendação da Cris antes de enviar. A decisão final continua humana e auditável."
secondaryAction={<button>Voltar</button>}
primaryAction={<button>Confirmar despacho</button>}
>
Origem: relatório reputacional validado há 2 min.
</PulsoDialog>Quando usar
- Confirmações de consequência média.
- Formulários curtos, com até quatro campos.
- Revelação focada que precisa de leitura exclusiva.
- Decisão que precisa pausar o fluxo antes de continuar.
Dialog vs Sheet vs Alert Dialog
| Superfície | Uso | Regra |
|---|---|---|
Dialog | Foco curto e decisão bloqueante | Interrompe o fluxo |
Sheet | Drill-down e edição contextual | Preserva contexto lateral |
Responsive Sheet | Mesmo fluxo em desktop/mobile | Adapta side/bottom sheet |
Alert Dialog | Ação destrutiva ou irreversível | Nomeia consequência e exige confirmação explícita |
Acessibilidade
- Focus trap dentro do Dialog.
Escfecha apenas quando não há perda de dados ou ação crítica pendente.- Focus retorna ao trigger ao fechar.
- Título e descrição precisam estar associados ao modal.
- Não use apenas cor para comunicar severidade.
Regras
- Dialog bloqueia; não use para conteúdo exploratório.
- Formulários longos vão para Sheet ou página dedicada.
- Ação primária precisa nomear o verbo real, não “OK”.
- Ação destrutiva ou irreversível usa
Alert Dialog. - Conteúdo assistido por IA precisa indicar base e incerteza.
Last updated on