Date Input

Pronto

Campo de data formatado dd/mm/aaaa com máscara automática e validação. Mais rápido que Date Picker quando o usuário SABE a data.

Usar quando

Data de nascimento, data de fato (ex: data do contrato, data da audiência conhecida). Power-users que digitam mais rápido que clicam.

Não usar quando

Data desconhecida que precisa exploração visual (use Date Picker). Mobile (use input type=date nativo).

Variantes

Data deve ser hoje ou no futuro.

Estados

Empty
Filled
Invalid (32/13/abcd)
Data inválida.
Disabled

Microinterações

MicrointeraçãoDisparada porComportamentoTiming
Auto-formatonChangeInsere "/" automaticamente após dd e mminstant
Cursor advancecompletou dd ou mmCursor pula para próxima parte (não obriga digitar /)instant
Validação on-blurblurVerifica data válida (32/13/aaaa = error)instant
Success morphdata válida on-blurÍcone ✓ aparece com pop250ms
Error inlinevalidação falhouBorda carmim + mensagem com ícone150ms
Sugestão "1985-05-15"detectou formato ISOMostra botão sugerindo "15/05/1985"instant

Acessibilidade

Acessibilidade — checklist

Teclado
TabFoco no input
0-9Digita; cursor avança nos slashes
BackspaceVolta inclusive sobre slashes (auto-skip)
EnterSubmete form
ARIA esperado
  • inputMode="numeric" // teclado numérico em mobile
  • pattern="\d{2}/\d{2}/\d{4}"
  • autoComplete="bday" // ou "off" se não for nascimento
  • aria-invalid="true" quando error
  • aria-describedby="hint" para placeholder
Notas
  • inputMode="numeric" mostra teclado numérico em mobile.
  • Hint visível "dd/mm/aaaa" — não use só placeholder.
  • Validação on-blur (não on-change — usuário ainda digitando).
  • Anti-pattern: 3 inputs separados (dd, mm, yyyy) — pior UX.

Código

'use client';
import { useState } from 'react';
import { T, TYPE, SP, RADIUS } from '@/lib/tokens';

function maskDate(s: string): string {
  const d = s.replace(/\D/g, '').slice(0, 8);
  if (d.length <= 2) return d;
  if (d.length <= 4) return d.slice(0, 2) + '/' + d.slice(2);
  return d.slice(0, 2) + '/' + d.slice(2, 4) + '/' + d.slice(4, 8);
}

function validate(s: string): string | null {
  if (s.length !== 10) return 'Use dd/mm/aaaa.';
  const [dd, mm, yyyy] = s.split('/').map(Number);
  if (mm < 1 || mm > 12) return 'Mês inválido.';
  const last = new Date(yyyy, mm, 0).getDate();
  if (dd < 1 || dd > last) return 'Dia inválido para o mês.';
  return null;
}

export function DateInput({ ...props }) {
  const [v, setV] = useState('');
  const [error, setError] = useState<string | null>(null);
  return (
    <input
      inputMode="numeric"
      placeholder="dd/mm/aaaa"
      value={v}
      onChange={(e) => setV(maskDate(e.target.value))}
      onBlur={() => setError(v.length > 0 ? validate(v) : null)}
      // ... styles padrão de Input
    />
  );
}

Regras

Faça

  • Máscara automática dd/mm/aaaa enquanto digita.
  • inputMode="numeric" para teclado mobile correto.
  • Validação on-blur (não on-change).
  • Aceite tanto colado "1985-05-15" quanto "15/05/1985".
  • Hint visível "dd/mm/aaaa" sob o campo.

Não faça

  • Não use 3 inputs separados (dd, mm, yyyy).
  • Não bloqueie digitação não-numérica (usuário pode estar em mobile com layout diferente).
  • Não valide on-change (interrompe).
  • Não force colar com formato específico — aceite variações.
  • Não esqueça de ano bissexto / dias do mês.

Tokens usados

TokenValorPapel
T.surface#FFFFFFbackground
T.border#E3DFD2borda default
T.borderInk#000000borda focus
T.carmim#A32E2Eerro de validação
T.verde#2F6B3Cícone success
TYPE.base13fontSize