Pular para o conteúdo

Toggle Group

templates/components/ToggleGroup

É um grupo de botões pressionáveis (on/off) que exprime uma SELEÇÃO entre opções: em type=single vira um controle segmentado (troca de visão, alinhamento) e em type=multiple vira barra de formatação/filtros (negrito+itálico, tags). O estado é um CONJUNTO de itens ativos — e é justamente esse conjunto que o usuário quer restringir, submeter, lembrar e rotular, sem tocar no visual.

Base congelada

Conteúdo

Seleção mínima obrigatória

Impede o estado vazio: quando ligado,…

Impede o estado vazio: quando ligado, o item ativo não pode ser desmarcado (exige sempre 1 pressionado). Essencial em type=single usado como troca de visão/alinhamento.

Dica por item (tooltip)

Mostra o aria-label do item como…

Mostra o aria-label do item como tooltip ao passar o mouse ou focar — indispensável para toggles só de ícone (negrito/itálico). Camada aditiva sobre o botão.

Lembrar seleção

Persiste os itens ativos (localStorage) e…

Persiste os itens ativos (localStorage) e os restaura no próximo carregamento — ideal para preferências como modo de visualização. Só comportamento e dados.

Rótulo do grupo

Adiciona um rótulo acessível e visível…

Adiciona um rótulo acessível e visível associado ao grupo (aria-labelledby), dando nome à seleção (ex.: 'Formatação:'). Conteúdo aditivo posicionável, não altera os itens. posicionável

Comportamento

Limite de itens ativos

Em type=multiple, define o máximo de…

Em type=multiple, define o máximo de itens simultaneamente pressionados (ex.: 3); ao atingir o teto, novos cliques são bloqueados até desmarcar outro. Puro comportamento.

Contador de selecionados

Texto vivo com a quantidade de…

Texto vivo com a quantidade de itens ativos, atualizado a cada toggle. Útil em multiple (filtros/tags). Conteúdo aditivo, sem alterar os itens. posicionável

Atalho de teclado por item

Vincula uma tecla a cada item…

Vincula uma tecla a cada item (ex.: Ctrl+B alterna o negrito), replicando o comportamento de uma barra de formatação real. Comportamental, sem tocar no visual.

Sincronizar com formulário

Emite input(s) hidden com o nome…

Emite input(s) hidden com o nome informado carregando o(s) valor(es) ativo(s), fazendo o grupo submeter como um campo de formulário comum (single=1 valor, multiple=vários).
Código gerado

Cole no Claude Code — ele acerta de primeira.

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

BASE CONGELADA (não mude por instância): Ficam congelados: variant (default/outline), size (sm/default/lg) e seu raio/altura, os cantos (rounded-lg, canto colado quando spacing=0), a fonte (text-sm font-medium), o gap por tokens (--spacing), o layout horizontal/vertical, o anel de foco (focus-visible ring-ring), os estados hover/disabled/aria-invalid e toda a a11y (role=group, aria-pressed, data-state=on/off, foco por teclado). A semântica single vs multiple e a estrutura ToggleGroup + ToggleGroup:Item também são base. Nada disso muda ao ligar/desligar uma capacidade.

USO: <twig:ToggleGroup variant="default" />

CAPACIDADES OPT-IN (ligue sem alterar o visual):
- Seleção mínima obrigatória: Impede o estado vazio: quando ligado, o item ativo não pode ser desmarcado (exige sempre 1 pressionado). Essencial em type=single usado como troca de visão/alinhamento. [toggle]- Limite de itens ativos: Em type=multiple, define o máximo de itens simultaneamente pressionados (ex.: 3); ao atingir o teto, novos cliques são bloqueados até desmarcar outro. Puro comportamento. [number]- Contador de selecionados: Texto vivo com a quantidade de itens ativos, atualizado a cada toggle. Útil em multiple (filtros/tags). Conteúdo aditivo, sem alterar os itens. [select → N / N de M / N selecionados]- Dica por item (tooltip): Mostra o aria-label do item como tooltip ao passar o mouse ou focar — indispensável para toggles só de ícone (negrito/itálico). Camada aditiva sobre o botão. [select → Acima / Abaixo / Esquerda / Direita]- Atalho de teclado por item: Vincula uma tecla a cada item (ex.: Ctrl+B alterna o negrito), replicando o comportamento de uma barra de formatação real. Comportamental, sem tocar no visual. [toggle]- Sincronizar com formulário: Emite input(s) hidden com o nome informado carregando o(s) valor(es) ativo(s), fazendo o grupo submeter como um campo de formulário comum (single=1 valor, multiple=vários). [text]- Lembrar seleção: Persiste os itens ativos (localStorage) e os restaura no próximo carregamento — ideal para preferências como modo de visualização. Só comportamento e dados. [toggle]- Rótulo do grupo: Adiciona um rótulo acessível e visível associado ao grupo (aria-labelledby), dando nome à seleção (ex.: 'Formatação:'). Conteúdo aditivo posicionável, não altera os itens. [text]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): Ficam congelados: variant (default/outline), size (sm/default/lg) e seu raio/altura, os cantos (rounded-lg, canto colado quando spacing=0), a fonte (text-sm font-medium), o gap por tokens (--spacing), o layout horizontal/vertical, o anel de foco (focus-visible ring-ring), os estados hover/disabled/aria-invalid e toda a a11y (role=group, aria-pressed, data-state=on/off, foco por teclado). A semântica single vs multiple e a estrutura ToggleGroup + ToggleGroup:Item também são base

Via MCP: tool get_component com {"id": "toggle-group"} · list_capabilities("toggle-group").

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

Spec machine-readable (JSON)

{
    "$schema_version": "1.0",
    "id": "toggle-group",
    "component": "ToggleGroup",
    "eixo": "ui",
    "particularidade": "É um grupo de botões pressionáveis (on/off) que exprime uma SELEÇÃO entre opções: em type=single vira um controle segmentado (troca de visão, alinhamento) e em type=multiple vira barra de formatação/filtros (negrito+itálico, tags). O estado é um CONJUNTO de itens ativos — e é justamente esse conjunto que o usuário quer restringir, submeter, lembrar e rotular, sem tocar no visual.",
    "base_congelada": "Ficam congelados: variant (default/outline), size (sm/default/lg) e seu raio/altura, os cantos (rounded-lg, canto colado quando spacing=0), a fonte (text-sm font-medium), o gap por tokens (--spacing), o layout horizontal/vertical, o anel de foco (focus-visible ring-ring), os estados hover/disabled/aria-invalid e toda a a11y (role=group, aria-pressed, data-state=on/off, foco por teclado). A semântica single vs multiple e a estrutura ToggleGroup + ToggleGroup:Item também são base. Nada disso muda ao ligar/desligar uma capacidade.",
    "props": [
        {
            "name": "variant",
            "type": "'default'|'outline'",
            "default": "default",
            "description": "The visual style variant. Defaults to `default` #}"
        },
        {
            "name": "size",
            "type": "'default'|'sm'|'lg'",
            "default": "default",
            "description": "The toggle group size. Defaults to `default` #}"
        },
        {
            "name": "type",
            "type": "'single'|'multiple'",
            "default": "multiple",
            "description": "Whether only one or multiple items can be active. Defaults to `multiple` #}"
        },
        {
            "name": "spacing",
            "type": "number",
            "default": "2",
            "description": "Gap between toggle group items. Defaults to `2` #}"
        },
        {
            "name": "orientation",
            "type": "'horizontal'|'vertical'",
            "default": "horizontal",
            "description": "The layout direction. Defaults to `horizontal` #}"
        },
        {
            "name": "disabled",
            "type": "boolean",
            "default": "false",
            "description": "Whether all items in the group are disabled. Defaults to `false` #}"
        }
    ],
    "capacidades": [
        {
            "id": "sele-o-m-nima-obrigat-ria",
            "nome": "Seleção mínima obrigatória",
            "descricao": "Impede o estado vazio: quando ligado, o item ativo não pode ser desmarcado (exige sempre 1 pressionado). Essencial em type=single usado como troca de visão/alinhamento.",
            "controle": "toggle",
            "opcoes": [],
            "posicionavel": false,
            "e_funcao": true,
            "como_plugar": "Capacidade opt-in (toggle). Ligue no configurador em /vitrine/ui/toggle-group; comportamento via controller Stimulus. Não altera a base."
        },
        {
            "id": "limite-de-itens-ativos",
            "nome": "Limite de itens ativos",
            "descricao": "Em type=multiple, define o máximo de itens simultaneamente pressionados (ex.: 3); ao atingir o teto, novos cliques são bloqueados até desmarcar outro. Puro comportamento.",
            "controle": "number",
            "opcoes": [],
            "posicionavel": false,
            "e_funcao": true,
            "como_plugar": "Capacidade opt-in (number). Ligue no configurador em /vitrine/ui/toggle-group; comportamento via controller Stimulus. Não altera a base."
        },
        {
            "id": "contador-de-selecionados",
            "nome": "Contador de selecionados",
            "descricao": "Texto vivo com a quantidade de itens ativos, atualizado a cada toggle. Útil em multiple (filtros/tags). Conteúdo aditivo, sem alterar os itens.",
            "controle": "select",
            "opcoes": [
                "N",
                "N de M",
                "N selecionados"
            ],
            "posicionavel": true,
            "e_funcao": true,
            "como_plugar": "Capacidade opt-in (select). Ligue no configurador em /vitrine/ui/toggle-group; comportamento via controller Stimulus. Não altera a base."
        },
        {
            "id": "dica-por-item-tooltip",
            "nome": "Dica por item (tooltip)",
            "descricao": "Mostra o aria-label do item como tooltip ao passar o mouse ou focar — indispensável para toggles só de ícone (negrito/itálico). Camada aditiva sobre o botão.",
            "controle": "select",
            "opcoes": [
                "Acima",
                "Abaixo",
                "Esquerda",
                "Direita"
            ],
            "posicionavel": false,
            "e_funcao": true,
            "como_plugar": "Capacidade opt-in (select). Ligue no configurador em /vitrine/ui/toggle-group; comportamento via controller Stimulus. Não altera a base."
        },
        {
            "id": "atalho-de-teclado-por-item",
            "nome": "Atalho de teclado por item",
            "descricao": "Vincula uma tecla a cada item (ex.: Ctrl+B alterna o negrito), replicando o comportamento de uma barra de formatação real. Comportamental, sem tocar no visual.",
            "controle": "toggle",
            "opcoes": [],
            "posicionavel": false,
            "e_funcao": true,
            "como_plugar": "Capacidade opt-in (toggle). Ligue no configurador em /vitrine/ui/toggle-group; comportamento via controller Stimulus. Não altera a base."
        },
        {
            "id": "sincronizar-com-formul-rio",
            "nome": "Sincronizar com formulário",
            "descricao": "Emite input(s) hidden com o nome informado carregando o(s) valor(es) ativo(s), fazendo o grupo submeter como um campo de formulário comum (single=1 valor, multiple=vários).",
            "controle": "text",
            "opcoes": [],
            "posicionavel": false,
            "e_funcao": true,
            "como_plugar": "Capacidade opt-in (text). Ligue no configurador em /vitrine/ui/toggle-group; comportamento via controller Stimulus. Não altera a base."
        },
        {
            "id": "lembrar-sele-o",
            "nome": "Lembrar seleção",
            "descricao": "Persiste os itens ativos (localStorage) e os restaura no próximo carregamento — ideal para preferências como modo de visualização. Só comportamento e dados.",
            "controle": "toggle",
            "opcoes": [],
            "posicionavel": false,
            "e_funcao": true,
            "como_plugar": "Capacidade opt-in (toggle). Ligue no configurador em /vitrine/ui/toggle-group; comportamento via controller Stimulus. Não altera a base."
        },
        {
            "id": "r-tulo-do-grupo",
            "nome": "Rótulo do grupo",
            "descricao": "Adiciona um rótulo acessível e visível associado ao grupo (aria-labelledby), dando nome à seleção (ex.: 'Formatação:'). Conteúdo aditivo posicionável, não altera os itens.",
            "controle": "text",
            "opcoes": [],
            "posicionavel": true,
            "e_funcao": true,
            "como_plugar": "Capacidade opt-in (text). Ligue no configurador em /vitrine/ui/toggle-group; comportamento via controller Stimulus. Não altera a base."
        }
    ],
    "snippet_uso": "<twig:ToggleGroup variant=\"default\" />",
    "exemplo_demo": "<twig:ToggleGroup variant=\"outline\" type=\"multiple\">\n    <twig:ToggleGroup:Item aria-label=\"Toggle bold\">\n        <twig:ux:icon name=\"lucide:bold\" />\n    </twig:ToggleGroup:Item>\n    <twig:ToggleGroup:Item aria-label=\"Toggle italic\">\n        <twig:ux:icon name=\"lucide:italic\" />\n    </twig:ToggleGroup:Item>\n    <twig:ToggleGroup:Item aria-label=\"Toggle strikethrough\">\n        <twig:ux:icon name=\"lucide:underline\" />\n    </twig:ToggleGroup:Item>\n</twig:ToggleGroup>",
    "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": "Ficam congelados: variant (default/outline), size (sm/default/lg) e seu raio/altura, os cantos (rounded-lg, canto colado quando spacing=0), a fonte (text-sm font-medium), o gap por tokens (--spacing), o layout horizontal/vertical, o anel de foco (focus-visible ring-ring), os estados hover/disabled/aria-invalid e toda a a11y (role=group, aria-pressed, data-state=on/off, foco por teclado). A semântica single vs multiple e a estrutura ToggleGroup + ToggleGroup:Item também são base",
    "mcp": {
        "tool": "get_component",
        "args": {
            "id": "toggle-group"
        }
    }
}