Skip to Content

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

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ícieUsoRegra
DialogFoco curto e decisão bloqueanteInterrompe o fluxo
SheetDrill-down e edição contextualPreserva contexto lateral
Responsive SheetMesmo fluxo em desktop/mobileAdapta side/bottom sheet
Alert DialogAção destrutiva ou irreversívelNomeia consequência e exige confirmação explícita

Acessibilidade

  • Focus trap dentro do Dialog.
  • Esc fecha 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

  1. Dialog bloqueia; não use para conteúdo exploratório.
  2. Formulários longos vão para Sheet ou página dedicada.
  3. Ação primária precisa nomear o verbo real, não “OK”.
  4. Ação destrutiva ou irreversível usa Alert Dialog.
  5. Conteúdo assistido por IA precisa indicar base e incerteza.
Last updated on