Pular para o conteúdo

Checkbox

templates/components/Checkbox

O Checkbox é um input nativo binário cuja singularidade é ter um terceiro estado nativo (indeterminado/parcial) e semântica de grupo (pai que controla filhos, "marcar todos"). É a peça central de fluxos de consentimento e conformidade — "Aceito os termos", declarações de EPI/SST — onde o valor precisa ser exigido, confirmado ou lembrado.

Base congelada

By clicking this checkbox, you agree to the terms.

Conteúdo

Estado indeterminado (tri-state)

Ativa o terceiro estado nativo do…

Ativa o terceiro estado nativo do checkbox (parcial): renderiza o glifo de traço no lugar do check, reaproveitando o mesmo quadro/cor/cantos. Usado no pai de um grupo com filhos só parcialmente marcados.

Pai marcar todos (hierarquia)

Um checkbox pai comanda um grupo…

Um checkbox pai comanda um grupo de filhos: marca/desmarca todos e assume automaticamente marcado, indeterminado ou vazio conforme o estado dos filhos. Puro comportamento, sem mudar o visual.

Contador do grupo

Exibe quantos itens do grupo estão…

Exibe quantos itens do grupo estão marcados (ex.: '3 de 12'). Conteúdo aditivo posicionável no topo ou no rodapé do grupo, espelhando o princípio de posição da Tabela. posicionável

Lembrar escolha

Persiste o valor localmente (localStorage) para…

Persiste o valor localmente (localStorage) para padrões como 'não mostrar novamente' ou consentimento de cookies, restaurando o estado na próxima visita. Comportamento aditivo, sem tocar na aparência.

Formato circular / raio do quadro ⚠️

TENTAÇÃO que NÃO passa no teste:…

TENTAÇÃO que NÃO passa no teste: tornar o quadro circular altera os 'cantos' congelados da base. É decisão de BASE (muda para todos em app.css), nunca um opt-in por instância — listado aqui como contraexemplo honesto.

Comportamento

Obrigatório com mensagem

Marca o checkbox como exigido (ex.:…

Marca o checkbox como exigido (ex.: 'Aceito os termos') e mostra uma mensagem de validação quando fica vazio no envio, reaproveitando o estilo aria-invalid já congelado na base. Só valida, não muda o visual.

Confirmar antes de alternar

Pede confirmação antes de aplicar a…

Pede confirmação antes de aplicar a mudança de estado — útil para desmarcar uma declaração de conformidade/EPI. Escolha em qual transição a confirmação dispara.

Habilitar só após ler (scroll-to-accept)

Mantém o checkbox no estado disabled…

Mantém o checkbox no estado disabled já congelado na base até o usuário rolar o texto dos termos até o fim, então o libera. Padrão clássico de consentimento/compliance; apenas comportamento de gate.
Código gerado

Cole no Claude Code — ele acerta de primeira.

Checkbox (UI) — Design System (Symfony UX Toolkit / shadcn)

BASE CONGELADA (não mude por instância): Ficam imutáveis: o quadro de 16px (size-4), cantos de 4px (rounded-[4px]), a borda border-input, o preenchimento primary quando marcado, o glifo de check (lucide:check size-3.5) como indicador, o anel de foco (focus-visible ring-ring), a opacidade 50% em disabled, o estilo destructive em aria-invalid, o input HTML nativo e toda a a11y (foco visível, semântica, label associável). Nenhum enricher pode tocar fonte, cor, cantos, tamanho ou espaçamento desse quadro — só somar comportamento ou conteúdo ao redor.

USO: <twig:Checkbox />

CAPACIDADES OPT-IN (ligue sem alterar o visual):
- Estado indeterminado (tri-state): Ativa o terceiro estado nativo do checkbox (parcial): renderiza o glifo de traço no lugar do check, reaproveitando o mesmo quadro/cor/cantos. Usado no pai de um grupo com filhos só parcialmente marcados. [toggle]- Pai marcar todos (hierarquia): Um checkbox pai comanda um grupo de filhos: marca/desmarca todos e assume automaticamente marcado, indeterminado ou vazio conforme o estado dos filhos. Puro comportamento, sem mudar o visual. [toggle]- Contador do grupo: Exibe quantos itens do grupo estão marcados (ex.: '3 de 12'). Conteúdo aditivo posicionável no topo ou no rodapé do grupo, espelhando o princípio de posição da Tabela. [select → N de M selecionados / N selecionados / N/M]- Obrigatório com mensagem: Marca o checkbox como exigido (ex.: 'Aceito os termos') e mostra uma mensagem de validação quando fica vazio no envio, reaproveitando o estilo aria-invalid já congelado na base. Só valida, não muda o visual. [toggle]- Confirmar antes de alternar: Pede confirmação antes de aplicar a mudança de estado — útil para desmarcar uma declaração de conformidade/EPI. Escolha em qual transição a confirmação dispara. [select → Ao marcar / Ao desmarcar / Sempre]- Habilitar só após ler (scroll-to-accept): Mantém o checkbox no estado disabled já congelado na base até o usuário rolar o texto dos termos até o fim, então o libera. Padrão clássico de consentimento/compliance; apenas comportamento de gate. [toggle]- Lembrar escolha: Persiste o valor localmente (localStorage) para padrões como 'não mostrar novamente' ou consentimento de cookies, restaurando o estado na próxima visita. Comportamento aditivo, sem tocar na aparência. [toggle]- Formato circular / raio do quadro: TENTAÇÃO que NÃO passa no teste: tornar o quadro circular altera os 'cantos' congelados da base. É decisão de BASE (muda para todos em app.css), nunca um opt-in por instância — listado aqui como contraexemplo honesto. [select → Quadrado 4px (base) / Circular]  (⚠️ borderline: revisar se não é decisão de base)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): 5) como indicador, o anel de foco (focus-visible ring-ring), a opacidade 50% em disabled, o estilo destructive em aria-invalid, o input HTML nativo e toda a a11y (foco visível, semântica, label associável)

Via MCP: tool get_component com {"id": "checkbox"} · list_capabilities("checkbox").

Spec crua: config/ds-specs/checkbox.json · Conectar o MCP.

Spec machine-readable (JSON)

{
    "$schema_version": "1.0",
    "id": "checkbox",
    "component": "Checkbox",
    "eixo": "ui",
    "particularidade": "O Checkbox é um input nativo binário cuja singularidade é ter um terceiro estado nativo (indeterminado/parcial) e semântica de grupo (pai que controla filhos, \"marcar todos\"). É a peça central de fluxos de consentimento e conformidade — \"Aceito os termos\", declarações de EPI/SST — onde o valor precisa ser exigido, confirmado ou lembrado.",
    "base_congelada": "Ficam imutáveis: o quadro de 16px (size-4), cantos de 4px (rounded-[4px]), a borda border-input, o preenchimento primary quando marcado, o glifo de check (lucide:check size-3.5) como indicador, o anel de foco (focus-visible ring-ring), a opacidade 50% em disabled, o estilo destructive em aria-invalid, o input HTML nativo e toda a a11y (foco visível, semântica, label associável). Nenhum enricher pode tocar fonte, cor, cantos, tamanho ou espaçamento desse quadro — só somar comportamento ou conteúdo ao redor.",
    "props": [],
    "capacidades": [
        {
            "id": "estado-indeterminado-tri-state",
            "nome": "Estado indeterminado (tri-state)",
            "descricao": "Ativa o terceiro estado nativo do checkbox (parcial): renderiza o glifo de traço no lugar do check, reaproveitando o mesmo quadro/cor/cantos. Usado no pai de um grupo com filhos só parcialmente marcados.",
            "controle": "toggle",
            "opcoes": [],
            "posicionavel": false,
            "e_funcao": true,
            "como_plugar": "Capacidade opt-in (toggle). Ligue no configurador em /vitrine/ui/checkbox; comportamento via controller Stimulus. Não altera a base."
        },
        {
            "id": "pai-marcar-todos-hierarquia",
            "nome": "Pai marcar todos (hierarquia)",
            "descricao": "Um checkbox pai comanda um grupo de filhos: marca/desmarca todos e assume automaticamente marcado, indeterminado ou vazio conforme o estado dos filhos. Puro comportamento, sem mudar o visual.",
            "controle": "toggle",
            "opcoes": [],
            "posicionavel": false,
            "e_funcao": true,
            "como_plugar": "Capacidade opt-in (toggle). Ligue no configurador em /vitrine/ui/checkbox; comportamento via controller Stimulus. Não altera a base."
        },
        {
            "id": "contador-do-grupo",
            "nome": "Contador do grupo",
            "descricao": "Exibe quantos itens do grupo estão marcados (ex.: '3 de 12'). Conteúdo aditivo posicionável no topo ou no rodapé do grupo, espelhando o princípio de posição da Tabela.",
            "controle": "select",
            "opcoes": [
                "N de M selecionados",
                "N selecionados",
                "N/M"
            ],
            "posicionavel": true,
            "e_funcao": true,
            "como_plugar": "Capacidade opt-in (select). Ligue no configurador em /vitrine/ui/checkbox; comportamento via controller Stimulus. Não altera a base."
        },
        {
            "id": "obrigat-rio-com-mensagem",
            "nome": "Obrigatório com mensagem",
            "descricao": "Marca o checkbox como exigido (ex.: 'Aceito os termos') e mostra uma mensagem de validação quando fica vazio no envio, reaproveitando o estilo aria-invalid já congelado na base. Só valida, não muda o visual.",
            "controle": "toggle",
            "opcoes": [],
            "posicionavel": false,
            "e_funcao": true,
            "como_plugar": "Capacidade opt-in (toggle). Ligue no configurador em /vitrine/ui/checkbox; comportamento via controller Stimulus. Não altera a base."
        },
        {
            "id": "confirmar-antes-de-alternar",
            "nome": "Confirmar antes de alternar",
            "descricao": "Pede confirmação antes de aplicar a mudança de estado — útil para desmarcar uma declaração de conformidade/EPI. Escolha em qual transição a confirmação dispara.",
            "controle": "select",
            "opcoes": [
                "Ao marcar",
                "Ao desmarcar",
                "Sempre"
            ],
            "posicionavel": false,
            "e_funcao": true,
            "como_plugar": "Capacidade opt-in (select). Ligue no configurador em /vitrine/ui/checkbox; comportamento via controller Stimulus. Não altera a base."
        },
        {
            "id": "habilitar-s-ap-s-ler-scroll-to-accept",
            "nome": "Habilitar só após ler (scroll-to-accept)",
            "descricao": "Mantém o checkbox no estado disabled já congelado na base até o usuário rolar o texto dos termos até o fim, então o libera. Padrão clássico de consentimento/compliance; apenas comportamento de gate.",
            "controle": "toggle",
            "opcoes": [],
            "posicionavel": false,
            "e_funcao": true,
            "como_plugar": "Capacidade opt-in (toggle). Ligue no configurador em /vitrine/ui/checkbox; comportamento via controller Stimulus. Não altera a base."
        },
        {
            "id": "lembrar-escolha",
            "nome": "Lembrar escolha",
            "descricao": "Persiste o valor localmente (localStorage) para padrões como 'não mostrar novamente' ou consentimento de cookies, restaurando o estado na próxima visita. Comportamento aditivo, sem tocar na aparência.",
            "controle": "toggle",
            "opcoes": [],
            "posicionavel": false,
            "e_funcao": true,
            "como_plugar": "Capacidade opt-in (toggle). Ligue no configurador em /vitrine/ui/checkbox; comportamento via controller Stimulus. Não altera a base."
        },
        {
            "id": "formato-circular-raio-do-quadro",
            "nome": "Formato circular / raio do quadro",
            "descricao": "TENTAÇÃO que NÃO passa no teste: tornar o quadro circular altera os 'cantos' congelados da base. É decisão de BASE (muda para todos em app.css), nunca um opt-in por instância — listado aqui como contraexemplo honesto.",
            "controle": "select",
            "opcoes": [
                "Quadrado 4px (base)",
                "Circular"
            ],
            "posicionavel": false,
            "e_funcao": false,
            "como_plugar": "REPROVADO no teste 'é função ou é base' — NÃO plugar como capacidade. É decisão de BASE: mude o token na fonte única assets/styles/app.css, valendo para TODOS os componentes."
        }
    ],
    "snippet_uso": "<twig:Checkbox />",
    "exemplo_demo": "<twig:Field:Group class=\"max-w-sm\">\n    <twig:Field orientation=\"horizontal\">\n        <twig:Checkbox id=\"terms-checkbox\" name=\"terms-checkbox\" />\n        <twig:Label for=\"terms-checkbox\">Accept terms and conditions</twig:Label>\n    </twig:Field>\n    <twig:Field orientation=\"horizontal\">\n        <twig:Checkbox id=\"terms-checkbox-2\" name=\"terms-checkbox-2\" checked />\n        <twig:Field:Content>\n            <twig:Field:Label for=\"terms-checkbox-2\">Accept terms and conditions</twig:Field:Label>\n            <twig:Field:Description>By clicking this checkbox, you agree to the terms.</twig:Field:Description>\n        </twig:Field:Content>\n    </twig:Field>\n    <twig:Field orientation=\"horizontal\" data-disabled>\n        <twig:Checkbox id=\"toggle-checkbox\" name=\"toggle-checkbox\" disabled />\n        <twig:Field:Label for=\"toggle-checkbox\">Enable notifications</twig:Field:Label>\n    </twig:Field>\n    <twig:Field:Label>\n        <twig:Field orientation=\"horizontal\">\n            <twig:Checkbox id=\"toggle-checkbox-2\" name=\"toggle-checkbox-2\" />\n            <twig:Field:Content>\n                <twig:Field:Title>Enable notifications</twig:Field:Title>\n                <twig:Field:Description>You can enable or disable notifications at any time.</twig:Field:Description>\n            </twig:Field:Content>\n        </twig:Field>\n    </twig:Field:Label>\n</twig:Field:Group>",
    "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": "5) como indicador, o anel de foco (focus-visible ring-ring), a opacidade 50% em disabled, o estilo destructive em aria-invalid, o input HTML nativo e toda a a11y (foco visível, semântica, label associável)",
    "mcp": {
        "tool": "get_component",
        "args": {
            "id": "checkbox"
        }
    },
    "props_nota": "Sem props próprias declaradas: a base repassa atributos nativos via {{ attributes }} (id, name, type, value, aria-*, data-*). Props específicas, quando existem, ficam nos subcomponentes."
}