Alert Dialog
templates/components/AlertDialog
Diálogo modal de CONFIRMAÇÃO que interrompe o usuário e exige uma decisão binária explícita sobre uma ação crítica/irreversível — por design não é dispensável por clique fora e sempre pareia um Cancelar com uma Ação ("Tem certeza absoluta?"). Por isso todo enriquecedor aqui regula o ATRITO e a SEGURANÇA dessa decisão, nunca a estética.
Base congelada
Capacidades 8
Conteúdo
Confirmação por digitação
Exige que o usuário digite uma…
Consentimento obrigatório (checkbox)
Insere um checkbox tipo Entendo que…
Atraso obrigatório na Ação
Mantém o botão de Ação desabilitado…
Foco inicial seguro
Escolhe qual botão recebe o foco…
Ícone de destaque no cabeçalho
Preenche o slot Media (já provido…
Lembrar decisão (não perguntar novamente)
Adiciona um checkbox que persiste a…
Comportamento
Ação assíncrona com carregamento
Ao confirmar, o botão de Ação…
Métodos de dispensa permitidos
Define quais gestos podem fechar o…
Claude Code
Cole no Claude Code — ele acerta de primeira.
AlertDialog (UX) — Design System (Symfony UX Toolkit / shadcn)
BASE CONGELADA (não mude por instância): Estrutura em <dialog> nativo com controller Stimulus `alert-dialog` (open/close, keydown.esc->close) e a11y por aria-labelledby (Title) + aria-describedby (Description). Congelados: cantos rounded-xl, espaçamento p-4/gap-4, bg-popover + ring-foreground/10, backdrop com blur/black-10 e transições open/starting; grid do Header (centralizado no mobile, alinhado à esquerda no size default, LTR/RTL), slot Media (size-10, bg-muted, rounded-md), Footer com border-t/bg-muted-50 e ordem flex-col-reverse -> sm:justify-end; tipografia cn-font-heading text-base/medium no Title e text-sm text-muted-foreground na Description; variantes/tamanhos padrão dos botoes (Cancel=outline, Action=default) e os tamanhos de Content (default/sm). Nada disso muda por instância.
USO: <twig:AlertDialog>…</twig:AlertDialog>
CAPACIDADES OPT-IN (ligue sem alterar o visual):
- Confirmação por digitação: Exige que o usuário digite uma frase-alvo (ex.: o nome do recurso ou EXCLUIR) num campo; a Ação só habilita quando o texto bate exatamente. Trava clássica de exclusão irreversível. [text]- Consentimento obrigatório (checkbox): Insere um checkbox tipo Entendo que esta ação é permanente entre a descrição e o rodapé; a Ação fica desabilitada até ser marcado. [toggle]- Atraso obrigatório na Ação: Mantém o botão de Ação desabilitado por N segundos com contagem regressiva no rótulo (Continuar (3)), forçando uma pausa antes de confirmar algo perigoso. [number]- Ação assíncrona com carregamento: Ao confirmar, o botão de Ação vira spinner e o dialog trava (Cancelar/ESC/backdrop bloqueados, permanece aberto) até a resposta do servidor — evita duplo-envio e fechamento acidental durante a operação. [toggle]- Foco inicial seguro: Escolhe qual botão recebe o foco ao abrir. Padrão seguro para ações destrutivas é o Cancelar, de modo que um Enter reflexo não confirme a exclusão. [select → Cancelar / Confirmar]- Ícone de destaque no cabeçalho: Preenche o slot Media (já provido pela base) com um ícone lucide que sinaliza a natureza do alerta. Conteúdo aditivo no slot existente — herda o bg-muted, não cria visual novo. [select → triangle-alert / trash-2 / info / circle-help / shield-alert]- Métodos de dispensa permitidos: Define quais gestos podem fechar o dialog. A base é não-dispensável por fora; esta capacidade afrouxa por opt-in, liberando ESC e/ou clique no backdrop para confirmações de menor risco. [multi → ESC / Clique fora (backdrop)]- Lembrar decisão (não perguntar novamente): Adiciona um checkbox que persiste a escolha do usuário (localStorage por id do dialog); nas próximas vezes o Trigger executa a Ação direto e pula o modal. [toggle]FAÇA:
- Use <twig:Nome> — a base é congelada, você é dono do template em templates/components/.
- Ligue apenas capacidades opt-in listadas (e_funcao=true); a aparência não muda ao ligá-las.
- Passe atributos extras (id, aria-*, name, data-*) via {{ attributes }}.
NÃO FAÇA:
- Não mude cor/fonte/cantos/espaçamento por instância — é decisão de BASE, na fonte única assets/styles/app.css.
- Não crie variante/fork para a mesma coisa — existe UMA base por componente.
- Não reimplemente o componente nem adicione toolchain Node.
TESTE ANTES DE MUDAR: "é função ou é base?" — função = capacidade opt-in; base = mude o token na fonte única (assets/styles/app.css), para todos.
A11Y (herdada da base): esc->close) e a11y por aria-labelledby (Title) + aria-describedby (Description). variantes/tamanhos padrão dos botoes (Cancel=outline, Action=default) e os tamanhos de Content (default/sm)
LLM / MCP
Via MCP: tool get_component com {"id": "alert-dialog"} · list_capabilities("alert-dialog").
Spec crua: config/ds-specs/alert-dialog.json · Conectar o MCP.
Spec machine-readable (JSON)
{
"$schema_version": "1.0",
"id": "alert-dialog",
"component": "AlertDialog",
"eixo": "ux",
"particularidade": "Diálogo modal de CONFIRMAÇÃO que interrompe o usuário e exige uma decisão binária explícita sobre uma ação crítica/irreversível — por design não é dispensável por clique fora e sempre pareia um Cancelar com uma Ação (\"Tem certeza absoluta?\"). Por isso todo enriquecedor aqui regula o ATRITO e a SEGURANÇA dessa decisão, nunca a estética.",
"base_congelada": "Estrutura em <dialog> nativo com controller Stimulus `alert-dialog` (open/close, keydown.esc->close) e a11y por aria-labelledby (Title) + aria-describedby (Description). Congelados: cantos rounded-xl, espaçamento p-4/gap-4, bg-popover + ring-foreground/10, backdrop com blur/black-10 e transições open/starting; grid do Header (centralizado no mobile, alinhado à esquerda no size default, LTR/RTL), slot Media (size-10, bg-muted, rounded-md), Footer com border-t/bg-muted-50 e ordem flex-col-reverse -> sm:justify-end; tipografia cn-font-heading text-base/medium no Title e text-sm text-muted-foreground na Description; variantes/tamanhos padrão dos botoes (Cancel=outline, Action=default) e os tamanhos de Content (default/sm). Nada disso muda por instância.",
"props": [
{
"name": "open",
"type": "boolean",
"default": "false",
"description": "Whether the dialog is open on initial render. Defaults to `false` #}"
},
{
"name": "id",
"type": "string",
"default": null,
"description": "Unique identifier used to generate internal AlertDialog IDs #}"
}
],
"capacidades": [
{
"id": "confirma-o-por-digita-o",
"nome": "Confirmação por digitação",
"descricao": "Exige que o usuário digite uma frase-alvo (ex.: o nome do recurso ou EXCLUIR) num campo; a Ação só habilita quando o texto bate exatamente. Trava clássica de exclusão irreversível.",
"controle": "text",
"opcoes": [],
"posicionavel": false,
"e_funcao": true,
"como_plugar": "Capacidade opt-in (text). Ligue no configurador em /vitrine/ux/alert-dialog; comportamento via controller Stimulus. Não altera a base."
},
{
"id": "consentimento-obrigat-rio-checkbox",
"nome": "Consentimento obrigatório (checkbox)",
"descricao": "Insere um checkbox tipo Entendo que esta ação é permanente entre a descrição e o rodapé; a Ação fica desabilitada até ser marcado.",
"controle": "toggle",
"opcoes": [],
"posicionavel": false,
"e_funcao": true,
"como_plugar": "Capacidade opt-in (toggle). Ligue no configurador em /vitrine/ux/alert-dialog; comportamento via controller Stimulus. Não altera a base."
},
{
"id": "atraso-obrigat-rio-na-a-o",
"nome": "Atraso obrigatório na Ação",
"descricao": "Mantém o botão de Ação desabilitado por N segundos com contagem regressiva no rótulo (Continuar (3)), forçando uma pausa antes de confirmar algo perigoso.",
"controle": "number",
"opcoes": [],
"posicionavel": false,
"e_funcao": true,
"como_plugar": "Capacidade opt-in (number). Ligue no configurador em /vitrine/ux/alert-dialog; comportamento via controller Stimulus. Não altera a base."
},
{
"id": "a-o-ass-ncrona-com-carregamento",
"nome": "Ação assíncrona com carregamento",
"descricao": "Ao confirmar, o botão de Ação vira spinner e o dialog trava (Cancelar/ESC/backdrop bloqueados, permanece aberto) até a resposta do servidor — evita duplo-envio e fechamento acidental durante a operação.",
"controle": "toggle",
"opcoes": [],
"posicionavel": false,
"e_funcao": true,
"como_plugar": "Capacidade opt-in (toggle). Ligue no configurador em /vitrine/ux/alert-dialog; comportamento via controller Stimulus. Não altera a base."
},
{
"id": "foco-inicial-seguro",
"nome": "Foco inicial seguro",
"descricao": "Escolhe qual botão recebe o foco ao abrir. Padrão seguro para ações destrutivas é o Cancelar, de modo que um Enter reflexo não confirme a exclusão.",
"controle": "select",
"opcoes": [
"Cancelar",
"Confirmar"
],
"posicionavel": false,
"e_funcao": true,
"como_plugar": "Capacidade opt-in (select). Ligue no configurador em /vitrine/ux/alert-dialog; comportamento via controller Stimulus. Não altera a base."
},
{
"id": "cone-de-destaque-no-cabe-alho",
"nome": "Ícone de destaque no cabeçalho",
"descricao": "Preenche o slot Media (já provido pela base) com um ícone lucide que sinaliza a natureza do alerta. Conteúdo aditivo no slot existente — herda o bg-muted, não cria visual novo.",
"controle": "select",
"opcoes": [
"triangle-alert",
"trash-2",
"info",
"circle-help",
"shield-alert"
],
"posicionavel": false,
"e_funcao": true,
"como_plugar": "Capacidade opt-in (select). Ligue no configurador em /vitrine/ux/alert-dialog; comportamento via controller Stimulus. Não altera a base."
},
{
"id": "m-todos-de-dispensa-permitidos",
"nome": "Métodos de dispensa permitidos",
"descricao": "Define quais gestos podem fechar o dialog. A base é não-dispensável por fora; esta capacidade afrouxa por opt-in, liberando ESC e/ou clique no backdrop para confirmações de menor risco.",
"controle": "multi",
"opcoes": [
"ESC",
"Clique fora (backdrop)"
],
"posicionavel": false,
"e_funcao": true,
"como_plugar": "Capacidade opt-in (multi). Ligue no configurador em /vitrine/ux/alert-dialog; comportamento via controller Stimulus. Não altera a base."
},
{
"id": "lembrar-decis-o-n-o-perguntar-novamente",
"nome": "Lembrar decisão (não perguntar novamente)",
"descricao": "Adiciona um checkbox que persiste a escolha do usuário (localStorage por id do dialog); nas próximas vezes o Trigger executa a Ação direto e pula o modal.",
"controle": "toggle",
"opcoes": [],
"posicionavel": false,
"e_funcao": true,
"como_plugar": "Capacidade opt-in (toggle). Ligue no configurador em /vitrine/ux/alert-dialog; comportamento via controller Stimulus. Não altera a base."
}
],
"snippet_uso": "<twig:AlertDialog>…</twig:AlertDialog>",
"exemplo_demo": "<twig:AlertDialog id=\"delete_account\">\n <twig:AlertDialog:Trigger>\n <twig:Button variant=\"outline\" {{ ...alert_dialog_trigger_attrs }}>Show Dialog</twig:Button>\n </twig:AlertDialog:Trigger>\n <twig:AlertDialog:Content>\n <twig:AlertDialog:Header>\n <twig:AlertDialog:Title>Are you absolutely sure?</twig:AlertDialog:Title>\n <twig:AlertDialog:Description>\n This action cannot be undone. This will permanently delete your\n account from our servers.\n </twig:AlertDialog:Description>\n </twig:AlertDialog:Header>\n <twig:AlertDialog:Footer>\n <twig:AlertDialog:Cancel>Cancel</twig:AlertDialog:Cancel>\n <twig:AlertDialog:Action>Continue</twig:AlertDialog:Action>\n </twig:AlertDialog:Footer>\n </twig:AlertDialog:Content>\n</twig:AlertDialog>",
"regras": {
"faca": [
"Use <twig:Nome> — a base é congelada, você é dono do template em templates/components/.",
"Ligue apenas capacidades opt-in listadas (e_funcao=true); a aparência não muda ao ligá-las.",
"Passe atributos extras (id, aria-*, name, data-*) via {{ attributes }}."
],
"nao_faca": [
"Não mude cor/fonte/cantos/espaçamento por instância — é decisão de BASE, na fonte única assets/styles/app.css.",
"Não crie variante/fork para a mesma coisa — existe UMA base por componente.",
"Não reimplemente o componente nem adicione toolchain Node."
]
},
"a11y": "esc->close) e a11y por aria-labelledby (Title) + aria-describedby (Description). variantes/tamanhos padrão dos botoes (Cancel=outline, Action=default) e os tamanhos de Content (default/sm)",
"mcp": {
"tool": "get_component",
"args": {
"id": "alert-dialog"
}
}
}