KDS
Forms

Input

Campo de texto de uma linha — estiliza qualquer tipo HTML nativo (text, email, password, search, file…).

Overview

Input é um <input> HTML nativo estilizado com tokens semânticos do KDS. Aceita qualquer type válido — text, email, password, number, search, tel, url, file — e adapta o teclado mobile quando aplicável (ex: email mostra @ no teclado iOS).

Estados visuais não são controlados por className: focus vem do browser (focus-visible), erro vem de aria-invalid (atributo ARIA), disabled do prop nativo. Esse desacoplamento permite que FormControl (@kalvner/kds/forms/form) ligue tudo automaticamente quando o input está dentro de um FormField.

Preview
Input padrão com placeholder.

Anatomy

<Input
  type="text"
  ├─ [data-slot="input"]
  └─ [aria-invalid] (set by FormControl quando há erro)
/>

Input é um único elemento — não é compound. Ícones laterais e botões de limpar são composições externas (wrapper relative + absolute), não props do próprio Input. Esse padrão simplifica a API e mantém o componente substituível.

Usage

import { Input } from "@kalvner/kds/forms/input";
import { Label } from "@kalvner/kds/forms/label";

export function EmailField() {
  return (
    <div className="grid gap-2">
      <Label htmlFor="email">Email</Label>
      <Input id="email" type="email" placeholder="voce@exemplo.com" />
    </div>
  );
}
Form row
Composição mínima — Label + Input.

Props

PropTipoDefaultDescrição
type'text' | 'email' | 'password' | 'number' | 'search' | 'tel' | 'url' | 'file' | ...'text'Qualquer type HTML nativo.
disabledbooleanfalseBloqueia interação.
readOnlybooleanfalsePermite seleção/cópia mas bloqueia edição.
placeholderstringHint dentro do campo (não substitui Label).
aria-invalidbooleanAciona ring vermelho — atribuído por FormControl.
...restReact.ComponentProps<'input'>Tudo de <input>: id, value, onChange, pattern, min, max.

Variants

Email
Validação nativa + teclado com @ no mobile.
Password
Mascara o valor enquanto digita.
Number
Teclado numérico mobile. Ainda chega como string.
File
Picker nativo. Estilize o botão interno via classes file:.

States

Disabled
Sem pointer events, opacidade reduzida.
Readonly
Selecionável, não editável.
Error
aria-invalid aplica o ring vermelho.
Digite um e-mail válido.
With leading icon
Wrapper relative + ícone absolute + pl-9.

Composition

Search field
Lupa à esquerda, botão de limpar à direita.

When to use

  • Qualquer entrada de uma linha — nome, e-mail, busca, slug, número.
  • Em formulários, em filtros, em campos de busca em headers.
  • Quando o valor cabe naturalmente em uma linha. Para textos longos (mais de ~80 caracteres ou múltiplas frases), use Textarea.

When not to use

  • Para textos multi-linha — Textarea.
  • Para escolha entre opções — Select, RadioGroup, ou Combobox.
  • Para alternar uma flag — Switch ou Checkbox.
  • Para upload com preview e drag-and-drop, considere uma composição custom além do type="file" nativo.

Best practices

  • Sempre pareie com Label. Mesmo quando o desenho usa placeholder como label flutuante, mantenha um <Label> visível. Placeholder some quando o usuário começa a digitar — sem Label, ele esquece o que estava preenchendo.
  • Mensagem de erro abaixo do input, nunca dentro. Substituir o placeholder por mensagem de erro confunde — o usuário precisa do contexto do que digitou.
  • Use inputMode quando o type não cobre o teclado ideal. Ex: <Input type="text" inputMode="numeric" pattern="[0-9]*" /> para CEP, código de verificação.
  • Evite reservar layout só com altura. O Input já tem altura fixa (h-9), o que evita CLS. Mensagens de erro devem aparecer em slots reservados via grid gap-2 no FormItem — ver [[ui/layout/cumulative-layout-shift]].

Accessibility

ConcernComportamento
LabelSempre vincule via htmlFor + id ou wrap o Input dentro de <Label>.
ErroUse aria-invalid="true" + aria-describedby apontando para a mensagem. FormControl faz isso automaticamente.
Disabled statedisabled é nativo — bloqueia foco e interação. Para apenas indicar visualmente, use aria-disabled.
AutocompleteDefina autoComplete apropriado (email, current-password, cc-number) para password managers e iOS autofill.
RequiredUse required HTML; combine com asterisco visual no Label.
Touch targetAltura padrão é 36px. Para mobile crítico, considere uma classe h-10 ou maior.
  • Label — Label canônico, par obrigatório.
  • Form — wrappers que ligam ARIA automaticamente.
  • Textarea — entrada multi-linha.
  • Select — quando a entrada é uma escolha de lista.

On this page