# Checkbox

> Componentes / Formulário e ação · Estado: **Em andamento** — Implementado e utilizável, mas ainda sem a validação completa de acessibilidade.

Caixa de marcar com rótulo, para escolhas independentes — cada uma liga ou desliga sozinha. Tem o estado parcialmente marcado, para o item-pai de um grupo, e a variante `aceite`, para o "Li e aceito os termos".

- Função: Formulário e ação
- Também chamado de: caixa de seleção, checkbox, aceite, termos de uso
- Mora em: `app/components/atoms/Checkbox.tsx`
- Página: [https://phorte-design-system.vercel.app/styleguide/peca/Checkbox](https://phorte-design-system.vercel.app/styleguide/peca/Checkbox)
- Ficha no Storybook: [components-base-checkbox](https://main--69b4847d498a9bd8659db9ba.chromatic.com/?path=/docs/components-base-checkbox--docs)
- Prévia ao vivo, sozinha: [https://phorte-design-system.vercel.app/previa/Checkbox/0](https://phorte-design-system.vercel.app/previa/Checkbox/0)
- Todas as peças: [https://phorte-design-system.vercel.app/llms.txt](https://phorte-design-system.vercel.app/llms.txt)

## Como usar no código

```tsx
import { Checkbox } from '@/app/components/atoms/Checkbox';

<Checkbox />
```

## Uso

### Variantes na ficha

1. [Interativo](https://phorte-design-system.vercel.app/previa/Checkbox/0)
2. [Estados](https://phorte-design-system.vercel.app/previa/Checkbox/1)
3. [Parcialmente marcado](https://phorte-design-system.vercel.app/previa/Checkbox/2)
4. [Com erro](https://phorte-design-system.vercel.app/previa/Checkbox/3)
5. [Aceite](https://phorte-design-system.vercel.app/previa/Checkbox/4)
6. [Grupo](https://phorte-design-system.vercel.app/previa/Checkbox/5)

Quando cada opção vale por si e a pessoa pode marcar várias, ou nenhuma — e quando a escolha só vale ao enviar o formulário.

### Quando não usar

Para uma escolha só entre várias, use o Radio. Para ligar algo com efeito imediato, o Toggle. Para filtrar uma lista na hora, o FilterGroup.

### Faça

- Escreva o rótulo como afirmação que a marca torna verdadeira: "Quero receber novidades".
- Agrupe opções relacionadas num `<fieldset>` com `<legend>`.
- Use `indeterminado` no item-pai quando só parte dos filhos está marcada.
- Use `variant="aceite"` só no aceite que libera o envio.

### Evite

- Usar `aceite` em opção comum: o vermelho diz "ainda falta", e opção comum não tem lado certo.
- Passar `aria-invalid` sem mensagem de erro: a caixa fica vermelha e muda. O erro vem do FormField, com o texto.
- Rótulo negativo ("Não quero receber…") — marcar para desligar confunde.

### Nota de uso

O estado de erro é **visível**, e não só anunciado: sai do mesmo `aria-invalid` que o `FormField` usa como fonte única. Passar `aria-invalid` sem passar a mensagem deixa o campo vermelho e mudo — as duas coisas andam juntas. `indeterminado` desenha um traço e o leitor anuncia "parcialmente marcado": é o item-pai de um grupo. A linha inteira é o `<label>`, com 44px de altura — a caixa continua com 16px. Nos três controles de marcação a `className` vai para o invólucro. **`variant="aceite"`** é para o aceite que libera o envio (termos de uso, contrato): vermelha enquanto falta, verde quando aceita. O vermelho ali é "ainda falta", não erro — não emite `aria-invalid`; o erro, se o envio for tentado, vem do `FormField`. Não use em opção comum, que não tem lado certo.

### Anatomia

1. **Caixa** — 16px, borda de controle; marcada, fundo vermelho de interface (ou verde, no `aceite`) com o visto branco.
2. **Rótulo** — Texto `text-sm` ao lado. A linha inteira é o `<label>`: tocar em qualquer ponto marca.

### Estados

| Estado | O que muda |
| --- | --- |
| Desmarcada | Caixa vazia, borda `--border-interactive`. No `aceite`: borda e fundo vermelhos claros. |
| Marcada | Fundo `--primary` com visto branco. No `aceite`: fundo `--success`. |
| Parcialmente marcada | `indeterminado`: traço no lugar do visto; o leitor anuncia "parcialmente marcado". |
| Foco | Anel `ring-ring` de 2px em volta da caixa, só no teclado. |
| Erro | `aria-invalid` (vindo do FormField): borda vermelha. |
| Desabilitada | Linha inteira a 50% de opacidade, cursor proibido e fora da ordem de Tab. |

### Comportamento

| Situação | O que acontece |
| --- | --- |
| Link dentro do rótulo | Clicar no link abre o destino e não marca a caixa: o `label` não ativa o controle quando o clique é num link (é o HTML). A prop `rotuloInterativo` que a E73 previa não foi criada por isso — conferido no teste da Newsletter. |
| Clique na caixa ou no texto | Marca ou desmarca — o rótulo é o `<label>` da caixa. |
| `indeterminado` muda | O componente liga a propriedade `indeterminate` do `<input>` por JavaScript — não existe atributo HTML para ela. |
| Aceite marcado | A caixa passa do vermelho ao verde; não emite `aria-invalid` em nenhum dos dois. |

### Relacionados

- [Radio](https://phorte-design-system.vercel.app/styleguide/md/Radio.md) — Uma escolha só, entre várias.
- [Toggle](https://phorte-design-system.vercel.app/styleguide/md/Toggle.md) — Liga e desliga com efeito imediato.
- [FormField](https://phorte-design-system.vercel.app/styleguide/md/FormField.md) — Rótulo, dica e erro em volta do controle.

## Especificação

### Propriedades

| Prop | Tipo | Padrão | Obrigatória | Descrição |
| --- | --- | --- | --- | --- |
| `variant` | `'padrao' \| 'aceite'` | `'padrao'` | não | Variante do `cva`. |
| `label` | `React.ReactNode` | — | não |  |
| `indeterminado` | `boolean` | `false` | não | Estado intermediário: "alguns marcados", no item-pai de um grupo. Liga o `indeterminate` do `<input>` — que só existe por JavaScript, não há atributo HTML — e o leitor de tela anuncia "parcialmente marcado". |

Aceita também: `Omit<React.InputHTMLAttributes<HTMLInputElement>, 'type'>`.

### Medidas

| Parte | Valor | Classe |
| --- | --- | --- |
| Caixa | 16 × 16px | `h-4 w-4` |
| Linha (alvo de toque) | 44px de altura | `min-h-alvo-toque` |

### Tokens de cor

| Token | Valor | Usado como |
| --- | --- | --- |
| `--primary` | #D42B2B | `bg-primary`, `border-primary` |
| `--success` | #2E844A | `bg-success`, `border-success` |
| `--background` | #FAFAFA | `bg-background` |
| `--border-interactive` | #8C8C8C | `border-border-interactive` |
| `--destructive` | #BA0517 | `border-destructive` |
| `--destructive-subtle` | #F9EBEC | `bg-destructive-subtle` |
| `--foreground` | #1A1A1A | `text-ink` |
| `--primary-foreground` | #FFFFFF | `text-primary-foreground` |

## Acessibilidade

### Teclado

| Tecla | Faz |
| --- | --- |
| Tab | Vai de caixa em caixa — num grupo, cada uma é uma parada (medido: Presencial, Ao vivo online, EAD, Semipresencial). |
| Espaço | Marca ou desmarca a caixa em foco. |
| Enter | Não faz nada — medido. Numa caixa, só o Espaço marca. |
| ↑ / ↓ | Não andam entre as caixas de um grupo — medido. Setas são do Radio. |

### Leitor de tela

- O nome acessível é o rótulo: a caixa e o texto estão no mesmo `<label>`.
- O visto e o traço são `aria-hidden`; o estado lido vem do `<input>` (marcado, não marcado, parcialmente marcado).

### O que sustenta o estado

Usa os padrões: formulario. Falta ouvir com leitor de tela: formulario.

## Status e recursos

| Tipo | Recurso | Status |
| --- | --- | --- |
| Código | `app/components/atoms/Checkbox.tsx` | Disponível |
| Ficha | https://main--69b4847d498a9bd8659db9ba.chromatic.com/?path=/docs/components-base-checkbox--docs | Disponível |
| Teste de acessibilidade | axe em `npm run test` | No gate de todo commit |
| Leitor de tela | Passada da E33 | Falta ouvir |
| Design | Figma | Desativado até a Fase 2 |

### Histórico

- `0298af8` 2026-09-30 — E147: fechamento da Entrega 11 — REPORT.md, verificação cross-agent e o gate estático estrito
- Histórico completo no GitHub: https://github.com/srbunnie/Pos-Phorte-Design-System/commits/main/app/components/atoms/Checkbox.tsx
