# RadioGroup

Agrupa os `Radio` e cuida da escolha única e da navegação por setas. Passe
`aria-label` ou aponte para um título com `aria-labelledby`: sem isso o grupo
existe para o mouse e não para o leitor de tela.

## No React Native

Traduz com `items` na raiz: não há `Radio` solto para compor, e tudo é controlado.

**O `label` é o `aria-label` do web com outro nome.** A página de lá já cobrava: sem nome, o grupo existe para o dedo e não para o leitor de tela. Aqui não havia como cobrar, e o buraco era pior do que faltar a prop: o `forValue` do subcaminho de formulário já entregava `accessibilityLabel`, mas o tipo é fechado e espalhamento em JSX não confere propriedade excedente, então o nome era **descartado em silêncio com o TypeScript verde**.

Ele não desenha nada: o texto visível é do `Field`, como no `Select` e no `Combobox`. Dentro de um `FormField`, repita ali o mesmo texto do `label` dele.

## Importação

```tsx
import { RadioGroup } from '@rivocode/ui'
```

## Exemplos

### Forma de pagamento

```tsx
import { Radio, RadioGroup } from '@rivocode/ui'

export function PaymentMethod() {
  return (
    <RadioGroup defaultValue="pix">
      <label className="flex items-center gap-3 text-base text-fg">
        <Radio value="pix" />
        Pix
      </label>
      <label className="flex items-center gap-3 text-base text-fg">
        <Radio value="boleto" />
        Boleto
      </label>
      <label className="flex items-center gap-3 text-base text-fg-disabled">
        <Radio value="cartao" disabled />
        Cartão, indisponível para esta nota
      </label>
    </RadioGroup>
  )
}
```

### Com rótulo

```tsx
import { Radio, RadioGroup } from '@rivocode/ui'

export function WithText() {
  return (
    <RadioGroup defaultValue="service">
      <Radio value="service">Prestação de serviço</Radio>
      <Radio value="product">Venda de produto</Radio>
      <Radio value="rent">Locação</Radio>
    </RadioGroup>
  )
}
```

## Props

| Prop | Tipo | Obrigatória | Desde | O que faz |
| --- | --- | --- | --- | --- |
| `defaultValue` | `unknown` |  | 0.4.0 | The uncontrolled value of the radio button that should be initially selected. |
| `disabled` | `boolean` |  | 0.4.0 | Whether the component should ignore user interaction. |
| `form` | `string` |  | 0.4.0 | Identifies the form that owns the radio inputs. |
| `inputRef` | `Ref<HTMLInputElement>` |  | 0.4.0 | A ref to access the hidden input element. |
| `name` | `string` |  | 0.4.0 | Identifies the field when a form is submitted. |
| `onValueChange` | `((value: unknown, eventDetails: { reason: "none"; event: Event; cancel: () => void; allowPropagation: () => void; isCanceled: boolean; isPropagationAllowed: boolean; trigger: Element \| undefined; }) => void)` |  | 0.4.0 | Callback fired when the value changes. |
| `readOnly` | `boolean` |  | 0.4.0 | Whether the user should be unable to select a different radio button in the group. |
| `render` | `ComponentRenderFn<HTMLProps, RadioGroupState> \| ReactElement<unknown, string \| JSXElementConstructor<any>>` |  | 0.4.0 | Allows you to replace the component's HTML element with a different tag, or compose it with another component. |
| `required` | `boolean` |  | 0.4.0 | Whether the user must choose a value before submitting a form. |
| `value` | `unknown` |  | 0.4.0 | The controlled value of the radio item that should be currently selected. |

Além dessas: repassa `className`, `style`, `id` e os demais atributos do elemento raiz.

## Partes

O componente se monta com as peças abaixo. Todas vêm de `@rivocode/ui`.

### Radio

O circulo, sem rótulo. O texto fica num `<label>` que envolve os dois, igual ao
Checkbox, para o clique no texto também marcar.

Use quando as opções cabem na tela e comparar entre elas importa. Passando de
umas cinco, o `Select` gasta menos espaço.

## O rótulo

Passe o texto como filho e o círculo sai dentro de um `<label>`:

```tsx
<RadioGroup defaultValue="pix">
  <Radio value="pix">Pix</Radio>
  <Radio value="boleto">Boleto</Radio>
</RadioGroup>
```

Sem filho, sai só o círculo, para quando o rótulo tiver estrutura própria.

## Partes

`classNames` veste cada parte pelo nome: `circle` é o círculo de fora,
`indicator` é a marca de dentro e `label` é o `<label>` que embrulha os dois.
`labelClassName` é o nome antigo de `classNames.label`, e continua valendo.

```tsx
<Radio value="pix" classNames={{ circle: 'size-5', indicator: 'size-2.5' }}>
  Pix
</Radio>
```

O respiro entre o círculo e o texto é o mesmo do `Checkbox` e do `Switch`, que
aparecem na mesma lista de formulário. E é menor do que o que separa uma opção
da seguinte, senão o rótulo ficaria mais perto da opção de baixo do que do
próprio círculo.

## O círculo marcado

O círculo marcado pinta `accent-text`, e não `accent`, com o ponto em
`surface-raised`. É a mesma troca da caixa do `Checkbox` e do trilho do
`Switch`: com a lima cheia o preenchimento media 1,21:1 sobre a página no tema
claro e 1,26:1 sobre o cartão, contra os 3:1 da WCAG 1.4.11. O ponto era
grafite e se lia, então o que sumia era a **fronteira do círculo** - a pessoa
via um ponto solto, e não uma opção escolhida.

Com `accent-text` a fronteira mede 5,55:1 sobre a página e 5,75:1 sobre o
cartão, e o ponto mede 5,75:1 dentro do preenchimento. No tema escuro os dois
papéis apontam para o mesmo valor, então lá o círculo não mudou de cor.

## Desabilitado

Desabilitado se pinta com token, e não com opacidade: o fundo passa a
`surface-raised` e a marca vai para `fg-disabled`. É a mesma receita do
`Checkbox`, borda inclusive. Ela não muda com o estado. Opacidade rebaixaria
tudo de uma vez, e a guarda de contraste do repositório não mede opacidade: o
par aprovado no arquivo de tema poderia reprovar na tela sem nada acusar.

| Prop | Tipo | Obrigatória | Desde | O que faz |
| --- | --- | --- | --- | --- |
| `value` | `unknown` | sim | 0.4.0 | The unique identifying value of the radio in a group. |
| `classNames` | `Partial<Record<"circle" \| "indicator" \| "label", string>>` |  | 0.5.0 | Classe por parte: `circle`, `indicator`, `label`. |
| `disabled` | `boolean` |  | 0.4.0 | Whether the component should ignore user interaction. |
| `inputRef` | `Ref<HTMLInputElement>` |  | 0.4.0 | A ref to access the hidden input element. |
| `labelClassName` | `string` |  | 0.4.0 | Classe do `<label>` de fora, quando ha texto. |
| `nativeButton` | `boolean` |  | 0.4.0 | Whether the component renders a native `<button>` element when replacing it via the `render` prop. |
| `readOnly` | `boolean` |  | 0.4.0 | Whether the user should be unable to select the radio button. |
| `render` | `ComponentRenderFn<HTMLProps, RadioRootState> \| ReactElement<unknown, string \| JSXElementConstructor<any>>` |  | 0.4.0 | Allows you to replace the component's HTML element with a different tag, or compose it with another component. |
| `required` | `boolean` |  | 0.4.0 | Whether the user must choose a value before submitting a form. |

## Ver também

- [Autocomplete](/componentes/autocomplete.md)
- [Calendar](/componentes/calendar.md)
- [Checkbox](/componentes/checkbox.md)
- [CheckboxGroup](/componentes/checkbox-group.md)
- [ColorPicker](/componentes/color-picker.md)
- [Combobox](/componentes/combobox.md)
- [Convenções da biblioteca](/convencoes.md): Provider, tokens e as regras que valem para toda peça
- [Índice completo](/llms.txt)
