Radio Group
templates/components/RadioGroup
Controle de escolha ÚNICA e mutuamente exclusiva entre N opções (role="radiogroup"), cada item um input radio nativo desenhado como círculo + ponto. Diferente do checkbox, o radio nativo não pode ser desmarcado clicando de novo — o que torna certas capacidades (limpar, pré-seleção) exclusivas da sua natureza.
Base congelada
Capacidades 9
Conteúdo
Título + descrição do grupo
Rótulo acessível do grupo (vira o…
Descrição por opção
Linha secundária de apoio abaixo do…
Ícone por opção
Ícone lucide aditivo junto ao label…
Desabilitar opções
Marca opções específicas como indisponíveis, usando…
Comportamento
Opção pré-selecionada
Define qual valor já vem marcado…
Limpar seleção
Botão para desmarcar tudo e voltar…
Validação obrigatória
Exige uma escolha antes de enviar;…
Orientação
Dispõe as opções em coluna ou…
Opção "Outro" + campo livre
Uma opção que, ao ser escolhida,…
Claude Code
Cole no Claude Code — ele acerta de primeira.
RadioGroup (UI) — Design System (Symfony UX Toolkit / shadcn)
BASE CONGELADA (não mude por instância): O desenho do controle: círculo size-4 rounded-full com border-input, cor primary quando marcado, ponto interno primary-foreground que escala ao selecionar, grid com gap-2, anel de foco (peer-focus-visible ring), e os estados disabled (opacity-50) e aria-invalid (destructive) já embutidos, com suporte RTL e semântica role="radiogroup". Fonte, cor, cantos, tamanho do controle e espaçamento são imutáveis.
USO: <twig:RadioGroup />
CAPACIDADES OPT-IN (ligue sem alterar o visual):
- Título + descrição do grupo: Rótulo acessível do grupo (vira o aria-labelledby do radiogroup) com subtítulo opcional acima das opções. [select → nenhum / só título / título + descrição]- Descrição por opção: Linha secundária de apoio abaixo do label de cada opção (ex.: o que cada plano/escolha inclui). [toggle]- Ícone por opção: Ícone lucide aditivo junto ao label de cada opção, posicionável no início ou no fim. [toggle]- Opção pré-selecionada: Define qual valor já vem marcado ao abrir (checked inicial) — ou nenhum. [select → nenhuma / primeira opção / opção específica]- Limpar seleção: Botão para desmarcar tudo e voltar ao estado sem escolha — algo que o radio nativo não permite clicando de novo. [toggle]- Validação obrigatória: Exige uma escolha antes de enviar; ativa o estado inválido (aria-invalid, já estilizado na base) e exibe mensagem de erro. [toggle]- Desabilitar opções: Marca opções específicas como indisponíveis, usando o estado disabled já embutido na base. [multi → 1ª opção / 2ª opção / 3ª opção / …]- Orientação: Dispõe as opções em coluna ou em linha, ajustando aria-orientation e o eixo das setas do teclado. [select → vertical / horizontal]- Opção "Outro" + campo livre: Uma opção que, ao ser escolhida, revela um input de texto para resposta livre; oculto e ignorado quando não selecionada. [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): O desenho do controle: círculo size-4 rounded-full com border-input, cor primary quando marcado, ponto interno primary-foreground que escala ao selecionar, grid com gap-2, anel de foco (peer-focus-visible ring), e os estados disabled (opacity-50) e aria-invalid (destructive) já embutidos, com suporte RTL e semântica role="radiogroup". Fonte, cor, cantos, tamanho do controle e espaçamento são imutáveis
LLM / MCP
Via MCP: tool get_component com {"id": "radio-group"} · list_capabilities("radio-group").
Spec crua: config/ds-specs/radio-group.json · Conectar o MCP.
Spec machine-readable (JSON)
{
"$schema_version": "1.0",
"id": "radio-group",
"component": "RadioGroup",
"eixo": "ui",
"particularidade": "Controle de escolha ÚNICA e mutuamente exclusiva entre N opções (role=\"radiogroup\"), cada item um input radio nativo desenhado como círculo + ponto. Diferente do checkbox, o radio nativo não pode ser desmarcado clicando de novo — o que torna certas capacidades (limpar, pré-seleção) exclusivas da sua natureza.",
"base_congelada": "O desenho do controle: círculo size-4 rounded-full com border-input, cor primary quando marcado, ponto interno primary-foreground que escala ao selecionar, grid com gap-2, anel de foco (peer-focus-visible ring), e os estados disabled (opacity-50) e aria-invalid (destructive) já embutidos, com suporte RTL e semântica role=\"radiogroup\". Fonte, cor, cantos, tamanho do controle e espaçamento são imutáveis.",
"props": [],
"capacidades": [
{
"id": "t-tulo-descri-o-do-grupo",
"nome": "Título + descrição do grupo",
"descricao": "Rótulo acessível do grupo (vira o aria-labelledby do radiogroup) com subtítulo opcional acima das opções.",
"controle": "select",
"opcoes": [
"nenhum",
"só título",
"título + descrição"
],
"posicionavel": false,
"e_funcao": true,
"como_plugar": "Capacidade opt-in (select). Ligue no configurador em /vitrine/ui/radio-group; comportamento via controller Stimulus. Não altera a base."
},
{
"id": "descri-o-por-op-o",
"nome": "Descrição por opção",
"descricao": "Linha secundária de apoio abaixo do label de cada opção (ex.: o que cada plano/escolha inclui).",
"controle": "toggle",
"opcoes": [],
"posicionavel": false,
"e_funcao": true,
"como_plugar": "Capacidade opt-in (toggle). Ligue no configurador em /vitrine/ui/radio-group; comportamento via controller Stimulus. Não altera a base."
},
{
"id": "cone-por-op-o",
"nome": "Ícone por opção",
"descricao": "Ícone lucide aditivo junto ao label de cada opção, posicionável no início ou no fim.",
"controle": "toggle",
"opcoes": [],
"posicionavel": true,
"e_funcao": true,
"como_plugar": "Capacidade opt-in (toggle). Ligue no configurador em /vitrine/ui/radio-group; comportamento via controller Stimulus. Não altera a base."
},
{
"id": "op-o-pr-selecionada",
"nome": "Opção pré-selecionada",
"descricao": "Define qual valor já vem marcado ao abrir (checked inicial) — ou nenhum.",
"controle": "select",
"opcoes": [
"nenhuma",
"primeira opção",
"opção específica"
],
"posicionavel": false,
"e_funcao": true,
"como_plugar": "Capacidade opt-in (select). Ligue no configurador em /vitrine/ui/radio-group; comportamento via controller Stimulus. Não altera a base."
},
{
"id": "limpar-sele-o",
"nome": "Limpar seleção",
"descricao": "Botão para desmarcar tudo e voltar ao estado sem escolha — algo que o radio nativo não permite clicando de novo.",
"controle": "toggle",
"opcoes": [],
"posicionavel": true,
"e_funcao": true,
"como_plugar": "Capacidade opt-in (toggle). Ligue no configurador em /vitrine/ui/radio-group; comportamento via controller Stimulus. Não altera a base."
},
{
"id": "valida-o-obrigat-ria",
"nome": "Validação obrigatória",
"descricao": "Exige uma escolha antes de enviar; ativa o estado inválido (aria-invalid, já estilizado na base) e exibe mensagem de erro.",
"controle": "toggle",
"opcoes": [],
"posicionavel": false,
"e_funcao": true,
"como_plugar": "Capacidade opt-in (toggle). Ligue no configurador em /vitrine/ui/radio-group; comportamento via controller Stimulus. Não altera a base."
},
{
"id": "desabilitar-op-es",
"nome": "Desabilitar opções",
"descricao": "Marca opções específicas como indisponíveis, usando o estado disabled já embutido na base.",
"controle": "multi",
"opcoes": [
"1ª opção",
"2ª opção",
"3ª opção",
"…"
],
"posicionavel": false,
"e_funcao": true,
"como_plugar": "Capacidade opt-in (multi). Ligue no configurador em /vitrine/ui/radio-group; comportamento via controller Stimulus. Não altera a base."
},
{
"id": "orienta-o",
"nome": "Orientação",
"descricao": "Dispõe as opções em coluna ou em linha, ajustando aria-orientation e o eixo das setas do teclado.",
"controle": "select",
"opcoes": [
"vertical",
"horizontal"
],
"posicionavel": false,
"e_funcao": true,
"como_plugar": "Capacidade opt-in (select). Ligue no configurador em /vitrine/ui/radio-group; comportamento via controller Stimulus. Não altera a base."
},
{
"id": "op-o-outro-campo-livre",
"nome": "Opção \"Outro\" + campo livre",
"descricao": "Uma opção que, ao ser escolhida, revela um input de texto para resposta livre; oculto e ignorado quando não selecionada.",
"controle": "toggle",
"opcoes": [],
"posicionavel": false,
"e_funcao": true,
"como_plugar": "Capacidade opt-in (toggle). Ligue no configurador em /vitrine/ui/radio-group; comportamento via controller Stimulus. Não altera a base."
}
],
"snippet_uso": "<twig:RadioGroup />",
"exemplo_demo": "<twig:RadioGroup class=\"w-fit\">\n <div class=\"flex items-center gap-3\">\n <twig:RadioGroup:Item id=\"r1\" name=\"spacing\" value=\"default\" />\n <twig:Label for=\"r1\">Default</twig:Label>\n </div>\n <div class=\"flex items-center gap-3\">\n <twig:RadioGroup:Item id=\"r2\" name=\"spacing\" value=\"comfortable\" checked />\n <twig:Label for=\"r2\">Comfortable</twig:Label>\n </div>\n <div class=\"flex items-center gap-3\">\n <twig:RadioGroup:Item id=\"r3\" name=\"spacing\" value=\"compact\" />\n <twig:Label for=\"r3\">Compact</twig:Label>\n </div>\n</twig:RadioGroup>",
"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": "O desenho do controle: círculo size-4 rounded-full com border-input, cor primary quando marcado, ponto interno primary-foreground que escala ao selecionar, grid com gap-2, anel de foco (peer-focus-visible ring), e os estados disabled (opacity-50) e aria-invalid (destructive) já embutidos, com suporte RTL e semântica role=\"radiogroup\". Fonte, cor, cantos, tamanho do controle e espaçamento são imutáveis",
"mcp": {
"tool": "get_component",
"args": {
"id": "radio-group"
}
},
"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."
}