Date Picker

Pronto

Calendário visual em popover para selecionar data. Use junto com Date Input quando o usuário precisa explorar (audiência futura, agenda).

Usar quando

Seleção de data em contexto onde calendário ajuda (ver fim de semana, ver feriados, ver semana). Audiências, prazos, eventos.

Não usar quando

Data de nascimento (use Date Input — usuário sabe a data). Mobile (use input type=date nativo).

Variantes

Maio 2026
SegTerQuaQuiSexSábDom

Apenas datas em 2026 são habilitadas. Feriados em vermelho.

Maio 2026
SegTerQuaQuiSexSábDom

05/05/2026 → 18/05/2026

Maio 2026
SegTerQuaQuiSexSábDom

Estados

Closed
Disabled
Inline aberto
Maio 2026
SegTerQuaQuiSexSábDom

Microinterações

MicrointeraçãoDisparada porComportamentoTiming
Open popoverclick no input/calendárioCalendário desce com fade + translateY200ms cubic-bezier(0.32,0.72,0,1)
Hover diamouseenter num diaBackground brassTint + ring brass100ms ease
Mês anterior/próximoclick chevronSlide horizontal (direção) + fade200ms ease
Today highlightrenderHoje tem ring brass sem ser selectedinstant
Selected dayclick num diaBackground ink + texto branco150ms ease
Range selectionclick num 2º dia (range mode)Background brassTint entre as datas200ms
Disabled dayfora de min/maxOpacity 0.3 + cursor not-allowedinstant

Acessibilidade

Acessibilidade — checklist

Teclado
TabFoco no botão calendário
Enter / SpaceAbre popover
← / →Move dia anterior/próximo
↑ / ↓Move semana anterior/próxima
Page Up/DownMês anterior/próximo
Shift+Page Up/DownAno anterior/próximo
EnterSeleciona dia em foco
EscFecha sem selecionar
ARIA esperado
  • role="dialog" aria-modal="true" para o popover
  • <table role="grid"><tr role="row"><td role="gridcell" aria-selected />
  • aria-label nos chevrons ("Mês anterior", "Próximo mês")
  • aria-current="date" no dia de hoje
Notas
  • Em mobile, prefira <input type="date"> nativo (UX melhor).
  • Calendário forense: marque feriados nacionais visualmente diferenciados.
  • Range: 2 cliques (start + end). Hover entre cliques mostra preview.
  • Sempre permita teclado completo — usuários power preferem teclar.

Código

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

interface DatePickerProps {
  value: Date | null;
  onChange: (d: Date | null) => void;
  min?: Date;
  max?: Date;
}

export function DatePicker({ value, onChange, min, max }: DatePickerProps) {
  const [open, setOpen] = useState(false);
  return (
    <div style={{ position: 'relative' }}>
      <button onClick={() => setOpen(!open)} style={{
        display: 'flex', alignItems: 'center', gap: SP[2], height: 36,
        padding: `0 ${SP[3]}px`, background: T.surface,
        border: `1px solid ${open ? T.borderInk : T.border}`, borderRadius: RADIUS.md,
        fontSize: TYPE.base, color: value ? T.ink : T.inkSubtle,
      }}>
        <Calendar size={14} color={T.inkMuted} />
        {value ? value.toLocaleDateString('pt-BR') : 'Selecionar data'}
      </button>
      {open && <Calendar value={value} onChange={onChange} min={min} max={max} />}
    </div>
  );
}

Regras

Faça

  • Calendário em PT-BR (semana começa segunda).
  • Marque feriados nacionais (calendário forense é crítico em jurídico).
  • Hoje sempre tem ring (mesmo se não selected).
  • Suporte teclado completo (← → ↑ ↓ PgUp PgDn Enter Esc).
  • Em mobile, use input nativo type=date.
  • Range: hover entre cliques mostra preview do range.

Não faça

  • Não use popover em mobile (use full-screen sheet ou nativo).
  • Não force seleção (deixe Esc fechar sem mudar).
  • Não esconda o input quando popover aberto.
  • Não dificulte navegar anos (ano-picker rápido se range > 5 anos).
  • Não use spinner numérico cru (UX ruim).

Tokens usados

TokenValorPapel
T.ink#0A0A0Abackground do dia selecionado
T.surface#FFFFFFbackground do popover
T.brassTintrgba(164,124,43,0.08)hover de dia
T.brass#A47C2Bring de "hoje"
T.shadowMd0 4px 14px ...sombra do popover
RADIUS.md12borderRadius