Input
Em andamentoCampo de texto de uma linha. A borda de 2px com foco diz se o que foi digitado já basta — cinza quando não há regra ou o dado ainda está incompleto (com ícone vermelho), verde com dado suficiente, vermelha só no erro de verdade —, sempre com ícone junto da cor.
- Função
- Formulário e ação
- Também chamado de
- campo de texto, caixa de texto, text field, input
- Mora em
- app/components/atoms/Input.tsx
- Última mudança
- 2026-09-30
Prévia
A peça ao vivo, vinda da ficha, na largura escolhida. Em larguras fixas, ela roda num quadro do tamanho de uma tela de verdade.
Na largura da página: 0px
Variantes na ficha
Lidas da ficha no build, na ordem do palco. Cada uma abre sozinha, sem o styleguide em volta — é o endereço que o palco carrega.
Quando usar
Para qualquer dado de uma linha — nome, e-mail, telefone, senha, CPF —, dentro de um FormField, que dá o rótulo, a dica e o erro.
Faça
- Use dentro de um FormField: é ele que liga rótulo, dica e erro ao campo.
- Dê uma regra (
validarouminLength) quando houver critério de "pronto" — é ela que liga o vermelho e o verde. - Use o
typecerto (email,tel,password): muda o teclado do celular. - Largura e margem pela
className; o<input>em si, porclassNameDoCampo.
Evite
- Usar o
placeholdercomo rótulo: ele some quando a pessoa começa a digitar. - Somar um
ring-pelaclassName: o foco já é a borda de 2px, e o anel extra é seu para conferir o contraste. - Confundir
readOnlycomdisabled: somente leitura é dado decidido que a pessoa vê e copia; desabilitado sai do Tab e não vai no envio.
Quando não usar. Para texto longo, um <textarea>. Para escolher entre opções conhecidas, o Select ou o Radio. Para buscar, o SearchBar, que já é um formulário de busca.
Nota de uso
O foco é a borda de 2px, e não um anel: cinza (--border-focus) com o campo vazio, vermelho com dado insuficiente, verde com dado suficiente — as quatro cores passam de 3:1. O contrato vem de campoVariants, o mesmo do Select e do SearchBar. Se você somar um ring- pela className, ele se soma à borda e é seu: confira o contraste contra o fundo. error pinta a borda e emite aria-invalid. A className vai para a caixa externa (largura, margem); para estilizar o <input> em si, use classNameDoCampo. `readOnly` ou `disabled`: somente leitura (tracejado) é para dado decidido que a pessoa precisa ver e copiar; desabilitado é para campo que não se aplica agora — sai da tabulação e não vai no envio.
Anatomia
As partes, na ordem em que o olho — e o teclado — passam.
- Caixa — Borda de controle, `px-4 py-3`, cantos `rounded-md`.
- Texto e placeholder — `text-sm`; placeholder em `--muted-foreground`.
- Ícone de estado — Só com regra: X vermelho (incompleto) ou visto verde (suficiente), à direita.
- Encaixes — `inicio` e `fim` (ícone ou botão dentro da caixa); `limpavel` põe o botão de limpar; `type="password"` ganha "Mostrar senha". Todo botão tem 44×44.
Estados
Os estados que a peça tem no código, e o que muda em cada um.
| Estado | O que muda |
|---|---|
| Padrão | Borda --border-interactive de 1px, vazio ou com dado. |
| Foco | Borda --border-focus de 2px (sombra interna, para o texto não pular). É o estado com foco quando não há regra ou o campo está vazio. |
| Incompleto | Com foco e regra não cumprida: a borda de foco (cinza, 2px) e o ícone X vermelho; anuncia "Ainda incompleto". Não é erro — o vermelho da borda fica para o erro vindo do formulário (E60). |
| Senha visível | "Mostrar senha" com aria-pressed="true": o campo passa a type="text". |
| Suficiente | Com foco e regra cumprida: borda verde de 2px e visto; anuncia "Completo". |
| Erro | error ou aria-invalid: borda vermelha, com ou sem foco, e aria-invalid no campo. |
| Somente leitura | readOnly: borda tracejada e fundo --muted. |
| Desabilitado | 50% de opacidade, cursor proibido, fora do Tab. |
Comportamento
| Situação | O que acontece |
|---|---|
| Digitar com regra | O ícone X some e a borda fica verde quando a regra passa — conferido no teste da ficha: três dígitos num CEP de oito ficam incompletos, sem aria-invalid. |
| Esc num campo limpável | Limpa e mantém o foco; o botão de limpar some com o campo vazio — conferido no teste da ficha. |
| Sair do campo | A borda volta ao padrão (ou ao vermelho, se houver erro de fora). |
| Sem regra | Não há invólucro nem ícone: é o <input> de sempre. |
| Dentro de um FormField com erro | O aria-invalid chega pelo FormField, e a borda vermelha sai do mesmo atributo. |
Relacionados
Como usar no código
A importação e o menor uso, lidos do arquivo. O … marca as props obrigatórias.
import { Input } from '@/app/components/atoms/Input';
<Input />Propriedades
Lidas do código da peça no build — não escritas à mão.
| Prop | Tipo | Padrão | Obrigatória | Descrição |
|---|---|---|---|---|
error | boolean | — | não | Pinta a borda de erro e emite aria-invalid: vermelho e anúncio saem da mesma fonte. |
classNameDoCampo | string | — | não | Classes do <input> em si. A className vai para a caixa externa — largura e margem —, como no Select. Sem encaixe nem regra não há invólucro, e as duas caem no mesmo elemento. |
validar | (valor: string) => boolean | — | não | Quando o dado digitado já é suficiente. Ex.: (v) => /\S+@\S+\.\S+/.test(v). Sem validar, o minLength serve de regra. |
inicio | React.ReactNode | — | não | Ícone (decorativo, com aria-hidden) ou botão no começo da caixa. |
fim | React.ReactNode | — | não | Ícone ou botão no fim da caixa. |
limpavel | boolean | — | não | Botão de limpar quando há texto; o Esc também limpa. |
rotuloDoLimpar | string | 'Limpar o campo' | não | Nome do botão de limpar. Diga o que se limpa: "Limpar busca". |
onLimpar | () => void | — | não | Chamado ao limpar. Num campo controlado, é aqui que o valor volta a vazio. |
Aceita também: React.InputHTMLAttributes<HTMLInputElement>.
Medidas
| Parte | Valor | Classe |
|---|---|---|
| Altura com texto `text-sm` | 46px (medido) | px-4 py-3 |
| Borda com foco | 2px (1px de borda + 1px de sombra interna) | shadow-[inset_0_0_0_1px_var(--border-focus)] |
Tokens de cor
Os tokens semânticos que o código da peça usa, com o valor de hoje em app/globals.css.
| Token | Valor | Usado como |
|---|---|---|
--destructive | #BA0517 | text-destructive |
--foreground | #1A1A1A | text-ink |
--muted | #F4F6F9 | bg-muted |
--muted-foreground | #595959 | text-muted-foreground |
--ring | var(--footer-red)), decisão da revisão 2. Se outra peça precisar
* dele como superfície, o nome vira de papel (ex.: --surface-brand-strong). */
--footer-red: #7D1B1B | ring-ring |
--success | #2E844A | text-success |
Teclado
| Tecla | Faz |
|---|---|
| Tab | Leva o foco ao campo; a borda engrossa. Desabilitado é pulado. |
| Letras | Digitam no campo; com regra, a borda e o anúncio mudam só quando o estado muda. |
| Enter | Dentro de um `<form>`, envia o formulário — comportamento nativo. |
Leitor de tela
O que é anunciado, e por quê.
- O anúncio de "Ainda incompleto" e "Completo" é educado (
aria-live="polite") e só muda quando o estado muda — não a cada tecla. - O erro de verdade — com mensagem — vem do FormField, por
aria-invalidearia-describedby.
O que sustenta o estado
Esta peça usa formulario, regiaoViva. O estado dela é o de quem já foi ouvido com leitor de tela nesses padrões — e não uma passada sobre esta peça em específico.
Falta ouvir: formulario, regiaoViva — ver docs/a11y-screen-reader-checklist.md.
Status e recursos
| Tipo | Recurso | Status |
|---|---|---|
| Código | app/components/atoms/Input.tsx | Disponível |
| Ficha | Storybook (abre em outra aba) | 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
Os últimos commits que tocaram o arquivo, lidos do git no build.
0298af82026-09-30E147: fechamento da Entrega 11 — REPORT.md, verificação cross-agent e o gate estático estrito
O histórico completo está no GitHub (abre em outra aba).