---
fonte: 01-canonicos/seed-componentes.md
versao_da_fonte: v1.43
secao: 07
titulo: "Select — `estável` · validado pelo Rafael em 2026-08-02 (v0.11, mock do custom corrigido na validação)"
sequencia: 9 de 98
bytes_do_corpo: 8840
md5_do_corpo: 9c026ae0ed0211732ae76a5e82215700
gerado_por: 06-validacao/geradores/gen-camada-ia.py
nota: fatia GERADA — o corpo abaixo é byte a byte o trecho do canônico; edite o canônico, nunca esta fatia. Canônico inteiro em https://ds.seed.eng.br/01-canonicos/seed-componentes.md
---
## 7. Select — `estável` · validado pelo Rafael em 2026-08-02 (v0.11, mock do custom corrigido na validação)

> **Consome o form-field (§2).** Abre a família de ESCOLHA do bloco (select → combobox → checkbox → radio → switch) e carrega a régua que governa todos.
>
> **Base de evidência (3 rodadas encadeadas, 2026-08-02):** R1 (canon) — GOV.UK ("último recurso" em serviço público, com pesquisa), NN/g dropdowns (limiares <5 radios / >15 combobox), USWDS (<7), M3 (6), Carbon (3), CMS.gov (janela 7–15 + regras satélites), Parliament/Bristol/Pelican. R2 (herda: nativo × custom + mobile) — a própria stack: shadcn mantém DOIS selects (custom Radix e Native Select), comunidade documenta o trade-off e a regra de não misturar. R3 (herda: o custom é seguro o bastante?) — **Sarah Higley (Microsoft): teste de usabilidade real com leitores — recriar o `<select>` nativo é impossível (semântica por plataforma, teclado inconsistente, mobile inteiramente diferente); ARIA 1.2 foi o padrão menos bugado (= o que o Radix implementa)**; Angular Material recomenda nativo p/ a11y. Decisões G1–G7 aprovadas pelo Rafael em 2026-08-02.

### 7.1 A régua unificada da família de escolha (G1 — governa 5 componentes)

| Opções | Componente | Fonte da faixa |
|---|---|---|
| 1 escolha binária de AÇÃO com efeito imediato | switch (§8) | Fluent: switch = ação |
| 1 escolha binária de STATUS confirmada no submit (consentimento, "li e aceito") | checkbox único (§10) — nunca switch | Fluent: checkbox = status · emenda v0.12 |
| 2–6, uma escolha | radio (§9) | NN/g <5 · M3 6 · USWDS <7 → adotamos 6 |
| 2–6, várias escolhas | checkbox (§10) | CMS/NN/g: multi em dropdown é proibido (G5) |
| 7–15 (teto ~20 no ERP denso — Fiori) | **select** | janela CMS 7–15 |
| >15, ou qualquer volume com busca necessária | combobox (§11) | NN/g >15 · Fiori 20–200 |

Supersede: esta régua ATUALIZA a linha de volume do §3.1 (que citava só o Fiori). No formulário público vale o espírito GOV.UK (G7): antes de aceitar um select, reformule a pergunta para caber em radios; no ERP denso, o select curto é ferramenta legítima de densidade — o "último recurso" nasceu do one-thing-per-page de governo, não de toolbars com 12 filtros.

### 7.2 As 7 decisões (G1–G7, aprovadas 2026-08-02)

| # | Decisão | Porquê | Descartado |
|---|---|---|---|
| G1 | Régua unificada (§7.1) | 6 fontes harmonizadas; uma régua, cinco componentes, zero sobreposição | Réguas por componente (a do §3.1 já divergia da NN/g) |
| G2 | **Nativo estilizado = PADRÃO** (site, público, TODO toque); **custom Radix permitido no produto desktop** quando a opção exige conteúdo rico (ícone de status, metadado). NUNCA misturar os dois no mesmo formulário; híbrido POR PLATAFORMA (nativo no toque, custom no desktop) é recomendado — coerência com o dispositivo, não mistura | Higley: recriar o nativo é impossível; Angular Material: nativo = melhor a11y; no toque o nativo abre o picker do OS (roda iOS/lista Android) com zero JS; Radix implementa ARIA 1.2 — o padrão MENOS bugado no teste da Higley, o que torna o custom aceitável onde o conteúdo justifica | Custom universal (assume o risco Higley sem necessidade); nativo universal (opção rica do ERP não cabe em `<option>` — só texto) |
| G3 | Rótulo sempre; placeholder "Selecione…" (option `disabled selected hidden`) SÓ sem default sensato; **default inteligente** quando a maioria escolhe a mesma opção | CMS: nunca substituir o rótulo pelo placeholder; default correto poupa a interação inteira | "Selecione…" universal (esconde o default útil); primeiro item como default acidental |
| G4 | Selecionar NUNCA muda contexto (não navega, não submete, não recarrega) | CMS + WCAG 3.2.2 On Input | Select-como-navegação (o anti-padrão clássico) |
| G5 | Multi-seleção em dropdown PROIBIDA → checkboxes; `optgroup`/grupos só com categorias reais | CMS: usuários não entendem multi em dropdown | `<select multiple>` (ctrl+clique: ninguém descobre) |
| G6 | Fronteiras formais armadas: binário→switch · 2–6→radio · >15/busca→combobox (que herdará a semântica ARIA 1.2 testada) | A família nasce coordenada, não em disputa | Cada item redescobrir seus limites |
| G7 | "Último recurso" contextualizado por superfície (§7.1) | O contexto da pesquisa GOV.UK é serviço público | Importar o dogma sem o contexto (mataria o select no ERP sem ganho) |

### 7.3 Anatomia e estados (variante nativa — a padrão)

`<select>` nativo com `appearance:none` + chevron SVG próprio (o nativo não estiliza a seta) sobre a moldura do form-field: mesma altura (44px md), mesma borda (4.74:1), mesmos 9 estados NO TRIGGER (o painel de opções aberto é do OS/browser — não estilizamos, e isso é a FEATURE: é o painel que o usuário do dispositivo conhece). Dark: o trigger segue os tokens; o painel nativo segue o OS — documentado como comportamento esperado, não bug. Variante custom (Radix): trigger idêntico; painel usa `surface-overlay` + `shadow-overlay` (tokens de elevação v1.1); opção rica = ícone 20px + texto + metadado opcional em `--seed-field-help-text`.

### 7.4 Contrato HTML

`<select>` + `<option>` com `value` estável (nunca o texto como valor) · placeholder: `<option value="" disabled selected hidden>Selecione…</option>` · grupos: `<optgroup label>` · `autocomplete` quando aplicável (`country`, `address-level1`…) · form-field completo em volta (rótulo/ajuda/erro herdados).

### 7.5 Microcopy

Rótulo nomeia a coisa ("Concessionária"), placeholder instrui a ação ("Selecione…") — nunca o contrário. Opções em sentence case, ordenadas por LÓGICA do domínio (frequência de uso > alfabética > alfabética como fallback); nunca "Escolha uma opção acima" como erro — o erro do form-field diz o quê: "Selecione a concessionária".

### 7.6 Código — essência

```css
.seed-select{appearance:none;-webkit-appearance:none;
  height:var(--seed-field-height-md);padding:0 40px 0 12px;width:100%;
  font-family:var(--seed-font-sans);font-size:14px;color:var(--seed-field-value);
  background:var(--seed-field-bg);border:1px solid var(--seed-field-border);
  border-radius:var(--seed-field-radius);cursor:pointer;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' width='16'%3E%3Cpath fill='%234D606C' d='M4.3 6.3 8 10l3.7-3.7 1 1L8 12 3.3 7.3l1-1Z'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right 12px center}
.seed-select:hover{border-color:var(--seed-field-border-hover)}
.seed-select:focus-visible{outline:none;box-shadow:var(--seed-focus-ring)}
.seed-select:invalid{color:var(--seed-field-placeholder)} /* placeholder-option selecionada */
[data-theme="dark"] .seed-select{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' width='16'%3E%3Cpath fill='%23ACBECA' d='M4.3 6.3 8 10l3.7-3.7 1 1L8 12 3.3 7.3l1-1Z'/%3E%3C/svg%3E")}
```

```tsx
/* Nativo (padrão — G2): */
export function NativeSelect(props: React.SelectHTMLAttributes<HTMLSelectElement> & { placeholder?: string }) {
  const { id, helpId, errId, invalid } = useField();
  return (
    <select id={id} aria-invalid={invalid || undefined}
      aria-describedby={cn(invalid && errId, helpId) || undefined}
      className="seed-select" {...props}>
      {props.placeholder && <option value="" disabled hidden>{props.placeholder}</option>}
      {props.children}
    </select>
  );
}
/* Custom (produto desktop, opção rica): shadcn <Select> (Radix, ARIA 1.2) com
   SelectTrigger reestilizado nos mesmos tokens do trigger nativo e
   SelectContent em surface-overlay + shadow-overlay. Regra G2: nunca os dois
   no mesmo formulário; no toque, o custom degrada para o nativo. */
```

### 7.7 Aplicação dos 7 testes (§1.12)

1. Container 3:1: trigger herda (4.74/4.50); chevron 4.66:1 (cinza-700 sobre branco, decorativo com redundância do próprio trigger). ✅ 2. Mecanismos: placeholder ≠ valor por COR (4.74 vs 13.86 — mesmo mecanismo do input); aberto/fechado pelo painel, não por tom. ✅ 3. Grayscale: chevron + moldura carregam o papel sem matiz. ✅ 4. Par: nativo × custom lado a lado no preview — triggers idênticos (é o objetivo: o usuário não deve notar a diferença fechado). ✅ 5. Regra do um: uma escolha por select (multi é proibido — G5). ✅ 6. Estado atual: valor selecionado sempre visível no trigger; placeholder denuncia o não-preenchido pela cor. ✅ 7. Polegar 360px: nativo abre o picker do OS — a melhor experiência de toque possível por definição; trigger 44px full-width. ✅

---

