Pular para o conteúdo

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

Are you absolutely sure?

This action cannot be undone. This will permanently delete your account from our servers.

Conteúdo

Confirmação por digitação

Exige que o usuário digite uma…

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.

Consentimento obrigatório (checkbox)

Insere um checkbox tipo Entendo que…

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.

Atraso obrigatório na Ação

Mantém o botão de Ação desabilitado…

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.

Foco inicial seguro

Escolhe qual botão recebe o foco…

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.

Ícone de destaque no cabeçalho

Preenche o slot Media (já provido…

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.

Lembrar decisão (não perguntar novamente)

Adiciona um checkbox que persiste a…

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.

Comportamento

Ação assíncrona com carregamento

Ao confirmar, o botão de Ação…

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.

Métodos de dispensa permitidos

Define quais gestos podem fechar o…

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.
Código gerado

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)

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"
        }
    }
}