# Ficha — Form-field (seed-componentes.md §2, v2.00)

> Gerada por `06-validacao/geradores/gen-vitrine.py` a partir do canon. Esta é a ficha INTEIRA: todas as linhas, com o texto completo de cada célula (a página mostra uma versão de uma tela, encurtada). Onde a seção não tem o item em subseção própria, a ficha diz "ver a seção" e não inventa. Seção completa: https://ds.seed.eng.br/canon/seed-componentes/02-form-field-campo-de-formulario-estavel-validado/ · fatia em Markdown: https://ds.seed.eng.br/10-publicacao/ia/seed-componentes/02-form-field-campo-de-formulario-estavel-validado.md

## Anatomia e partes

| Slot · Elemento | Regras |
|---|---|
| A · Rótulo (`<label for>`) | Sempre visível, sempre no topo (nunca placeholder como rótulo; nunca flutuante; nunca à esquerda). Montserrat SemiBold 14px, `--seed-field-label` (13.86:1). Sufixo `(opcional)` em Regular, `--seed-field-optional-text`. Variante `label-hidden` (visually-hidden, permanece p/ leitor de tela) só quando o contexto torna o rótulo redundante — ex.: campo de busca com ícone e placeholder "Buscar…" — regra Polaris: usar com muito critério |
| B · Ajuda pré-digitação (exceção) | Entre rótulo e controle SOMENTE quando a instrução precisa ser lida ANTES de digitar (formato obrigatório complexo, decisão pré-preenchimento). Padrão é (D) |
| C · Controle | Slot genérico. Altura md 44px (alvo de toque WCAG, igual botão), sm 32px (densidade desktop), lg 52px. Radius `--seed-radius-md`. Borda 1px `--seed-field-border` (4.74:1 — é ela que identifica o controle, WCAG 1.4.11). Placeholder: DESENCORAJADO; quando usado, só exemplo de formato prefixado "Ex.:" — nunca instrução, nunca rótulo |
| D · Zona de mensagem | Ajuda: `--seed-field-help-text` (6.55:1 — acima do piso AA, na direção do 7:1 que o GOV.UK adotou após pesquisa). Erro: ícone ⚠ + texto `--seed-field-error-text` (7.18:1), prefixo "Erro:" visually-hidden p/ leitores de tela. Erro substitui a ajuda (B2); a mensagem de erro DEVE conter a instrução completa de correção (regra editorial que fecha o buraco da substituição). Sem reserva de altura: shift de 1 linha aceito (M3: substituição existe justamente p/ minimizar bump de layout) |
| E · Contador | Só quando há limite real. JetBrains Mono 12px (dado de medição = mono, regra dos tokens v1.1). Formato `usados/limite`. SUPERSEDE (v0.10): a política completa do contador vive no §6.3 (padrão GOV.UK) — o campo NUNCA trunca com `maxlength` duro; exceder o limite vira estado de ERRO com a contagem do excesso. A versão v0.6–v0.9 desta linha ('ao exceder, vira mensagem de erro' com maxlength no exemplo) fica substituída: o maxlength duro truncava colagem silenciosamente — perda de dado pega na pesquisa do textarea |

No canon: [§2.2 Anatomia — 5 slots](https://ds.seed.eng.br/canon/seed-componentes/02-form-field-campo-de-formulario-estavel-validado/#sec-2-2-anatomia-5-slots)

## Propriedades e variantes

A seção não traz este item em subseção própria — ver a seção §2 (https://ds.seed.eng.br/canon/seed-componentes/02-form-field-campo-de-formulario-estavel-validado/).

## Estados

| Estado | Sinais (light) · Regras |
|---|---|
| default | borda `--seed-field-border` (4.74:1) |
| hover | borda `--seed-field-border-hover` · transição 100ms produtiva. O ERRO VENCE O SOBREVOO (`PR-P133`, veredito dele, verbatim: "A" — "(a) erro vence o sobrevoo (padrão de mercado)", 2026-10-10): o campo em erro (`aria-invalid="true"`; no invólucro, `data-invalid="true"`) MANTÉM a borda `--seed-field-border-error` sob o ponteiro. A regra de sobrevoo não se aplica a campo em erro (`:not([aria-invalid="true"])`) — a vitória é por EXCLUSÃO no seletor, nunca por especificidade ou ordem das regras, que mudam sem aviso (medido: a regra do sobrevoo do `.seed-field__control` tem especificidade 0,4,0 e a do erro 0,2,0, e o vermelho se perdia). Mesma exclusão que já valia para inativo e somente-leitura. O `select` (§7) segue a mesma regra (`PR-P149`, folha de 2026-10-10 gravada às 11:22Z, F5 = a): `.seed-select:hover:not([aria-invalid="true"])` Invólucro com borda (`.sel__caixa` do seletor de pessoa, `.busca-campo` da busca; `PR-P148`, resposta da sessão de 2026-10-11): o erro pode estar no controle INTERNO, não no invólucro — a exclusão do sobrevoo do invólucro é `:not([aria-invalid="true"]):not(:has([aria-invalid="true"]))`; o `input` solto (`.cal__hora input`, `.filtros input[type="search"]`) e o `select` (`select:hover`, genérico e do hero do painel) levam só o `:not([aria-invalid="true"])`. |
| focus | `--seed-focus-ring` (anel, NÃO engrossar borda) · mecanismo de foco ≠ mecanismo de erro (GOV.UK removeu borda grossa no erro por confundir com foco) |
| filled | valor em `--seed-field-value` (13.86:1) · valor ≠ placeholder tem que ser óbvio (por isso placeholder é 4.74 e valor 13.86) |
| error | borda `--seed-field-border-error` (a MESMA cor do texto de erro, 7.18:1 no claro / 7.56:1 no escuro; igualada na v1.40 dos tokens, `CT-P28`) + ícone ⚠ + mensagem (7.18:1) + `aria-invalid` · NUNCA só cor (WCAG 1.4.1): são 3 sinais. Erro nunca aparece antes de interação real (B4). Nas telas e bancadas de referência que pintavam a borda do campo em erro com `--seed-feedback-danger-border` (2,01:1 no claro, 2,11:1 no escuro contra o fundo, abaixo do piso de 3:1 da SC 1.4.11 — `CT-P25`), a borda passa a usar a cor do texto de erro de campo, `--seed-field-error-text` (7,18:1 / 8,49:1 no canon 2.5; token que já existe, nenhum valor novo) — veredito dele na folha 9, M7 = "a" (2026-10-18 19:02Z; aplicado em 2026-10-23, `PR-P182`). `--seed-feedback-danger-border` fica só para a borda de caixa de ALERTA, nunca de campo; o `banco-formfield` seguiu com o token próprio `--seed-field-border-error` (5,19:1 / 5,52:1, já ≥ 3:1) até a v1.40 dos tokens; desde então `--seed-field-border-error` vale o mesmo que `--seed-field-error-text` (vermelho-700 no claro, vermelho-300 no escuro; nenhum hex novo; 7,18:1 e 7,56:1 sobre o fundo do campo, todas as superfícies da prova ≥ 5,95:1) — veredito dele, folha 13, P4 = "a" (2026-10-28; letra da folha: "igualar: o token `--seed-field-border-error` passa a ter a cor do texto de erro"; `CT-P28`). Prova: `06-validacao/provas/borda-erro/prova-borda-erro.py`. |
| success | borda `--seed-field-border-success` (4.60:1) + ícone ✓ + mensagem opcional · só onde confirma algo real (B6) |
| warning (v0.7) | borda `--seed-field-border-warning` (4.82:1) + ícone ▲ + mensagem (6.68:1) · Guarda-corpo duro: SÓ para plausibilidade — dado válido em formato, mas incomum ("consumo 10× acima da sua média — confira"). NUNCA para obrigatoriedade, NUNCA bloqueia submit. Sem o guarda-corpo, warning banaliza e treina a ignorar avisos (por isso o GOV.UK nem o tem). Origem: SAP Fiori/Carbon (ERP) |
| disabled | fundo `surface-sunken` + texto `text-disabled` + `cursor:not-allowed` · USO RESTRITO (USWDS: contraste baixo, invisível p/ teclado e leitor de tela) — preferir campo habilitado com validação, ou readonly. Nunca esconder informação necessária num campo disabled |
| readonly | fundo `surface-sunken`, SEM borda de controle, texto pleno (12.75:1), focável, copiável · estado de primeira classe (Fiori/USWDS/Polaris): exibe dado não-editável NESTE contexto (ex.: UC vinda do cadastro). Readonly ≠ disabled: readonly participa do fluxo (tab, cópia, leitor de tela); não recebe estados de validação (Fiori) |

No canon: [§2.4 Estados — 9 (os 6 obrigatórios do §0 + readonly, success e warning¹)](https://ds.seed.eng.br/canon/seed-componentes/02-form-field-campo-de-formulario-estavel-validado/#sec-2-4-estados-9-os-6-obrigatorios-do-0-readonly-success-e)

## Acessibilidade

`<label for>` sempre (nunca div-rotulada) · `aria-describedby` na ordem erro ANTES da ajuda (`"err-id help-id"` — AUI: o erro é anunciado primeiro) · `aria-invalid` só após validação real, NUNCA no estado inicial (W3C ARIA21), e SEMPRE com valor explícito `"true"` — nunca `toggleAttribute`, que grava o atributo com valor vazio: `[aria-invalid="true"]` do CSS não casa e a borda de erro some (bug flagrado na validação executada de 2026-08-03) · mensagem de erro com prefixo "Erro:" visually-hidden · erro dinâmico anunciado (região `aria-live="assertive"` ou `role="alert"`) · ícones de estado com par textual (1.4.1) · foco: anel, nunca borda engrossada · contraste: TODOS os pares da §2.5 medidos ≥4.5:1 texto e ≥3:1 não-texto · zoom 400%: layout de coluna única resiste · toque ≥44px no md.

No canon: [§2.9 Acessibilidade](https://ds.seed.eng.br/canon/seed-componentes/02-form-field-campo-de-formulario-estavel-validado/#sec-2-9-acessibilidade)

## Faça · não faça

As decisões do canon (faça) e a alternativa que cada uma descartou (não faça) — todas as 13, na ordem do canon.

| faça (decisão) | não faça (descartado) |
|---|---|
| B1 — Ajuda ABAIXO do controle; exceção: instrução pré-digitação vai acima | Hint sempre acima (GOV.UK — contexto one-thing-per-page de governo, não ERP denso) |
| B2 — Erro SUBSTITUI a ajuda + regra editorial (erro contém a correção completa) | Empilhar ajuda+erro (dobra a altura no pior momento); reservar altura fixa (desperdiça vertical em ERP) |
| B3 — Produto (SIGA/chat): marcar SÓ `(opcional)`. Formulários públicos de conversão: marcar AMBOS (`*` + `(opcional)`) | Regra única para os dois contextos (a indústria não tem consenso único — tem consenso POR contexto); asterisco no SIGA (ruído: quase tudo é obrigatório) |
| B4 — Validação onBlur com reward-early/punish-late + error summary no submit | Validar só no submit (GOV.UK — governo); validar enquanto digita desde a 1ª tecla (validação prematura, irrita — Baymard) |
| B5 — Arquitetura de máscara: REGISTRY EXTENSÍVEL, valor canônico sem formatação, telefone em E.164 | Enum fechado de máscaras BR (proposta da rodada 3 — fecharia a porta p/ 0800, EUA e máscaras futuras) |
| B6 — Estado success EXISTE, com parcimônia: só onde a confirmação carrega informação real | Sem success (perde o ganho em campos críticos: e-mail, documento, disponibilidade); success universal (ruído verde decorativo — GOV.UK desaconselha com razão) |
| Form-field como componente-base do bloco | Especificar label/ajuda/erro dentro de cada item (deriva incoerência) |
| Ajuda em cinza-700 (6.55:1), não cinza-600 | cinza-600 (4.74 — passa AA mas repete o erro que o GOV.UK corrigiu) |
| Erro texto em vermelho-700 (7.18:1), borda em vermelho-600 | Tudo em vermelho-500 (4.30:1 medido — serve p/ borda ≥3, mas REPROVA texto normal <4.5) |
| Borda dark = cinza-500 (4.50:1) | Reusar o token do botão outline (papéis diferentes: ação pontual vs grade de campos) |
| Foco = anel; erro = cor de borda + ícone + texto | Engrossar borda no erro (colisão de sinal) |
| Contador em JetBrains Mono | Montserrat (números dançam sem tabular) |
| ViaCEP com fallback manual sempre | CEP obrigatório via API (bloqueio real de cadastro) |

No canon: [§2.3 As 6 decisões estruturais (aprovadas 2026-08-02)](https://ds.seed.eng.br/canon/seed-componentes/02-form-field-campo-de-formulario-estavel-validado/#sec-2-3-as-6-decisoes-estruturais-aprovadas-2026-08-02) · [§2.13 Decisões deste item (além de B1–B6, com alternativas descartadas)](https://ds.seed.eng.br/canon/seed-componentes/02-form-field-campo-de-formulario-estavel-validado/#sec-2-13-decisoes-deste-item-alem-de-b1-b6-com-alternativas)

## Relacionados

Todas as seções do componentes citadas no texto desta seção (8), da mais citada para a menos:

- §0 [Fundamentos de componente](https://ds.seed.eng.br/canon/seed-componentes/00-fundamentos-de-componente-valem-para-todos-os/) — 1×
- §1 [Botão](https://ds.seed.eng.br/canon/seed-componentes/01-botao-estavel/) — 1×
- §3 [Input de texto](https://ds.seed.eng.br/canon/seed-componentes/03-input-de-texto-estavel-validado-pelo-rafael-em/) — 1×
- §6 [Textarea](https://ds.seed.eng.br/canon/seed-componentes/06-textarea-estavel-validado-pelo-rafael-em-2026/) — 1×
- §7 [Select](https://ds.seed.eng.br/canon/seed-componentes/07-select-estavel-validado-pelo-rafael-em-2026-08/) — 1×
- §8 [Switch](https://ds.seed.eng.br/canon/seed-componentes/08-switch-estavel-validado-pelo-rafael-em-2026-08/) — 1×
- §9 [Radio](https://ds.seed.eng.br/canon/seed-componentes/09-radio-estavel-validado-pelo-rafael-em-2026-08/) — 1×
- §10 [Checkbox](https://ds.seed.eng.br/canon/seed-componentes/10-checkbox-estavel-validado-pelo-rafael-em-2026/) — 1×
