KDS
Forms

DatePicker

Composto Popover + Calendar — seleção de data em forms compactos.

Overview

DatePicker é o padrão composto que junta Popover

  • Calendar num único componente — botão que mostra a data escolhida, popover com a grade de seleção. É o equivalente a um input de data, mas com UI rica e teclado-acessível.

KDS exporta esse composto pronto pra economizar boilerplate. Para intervalo (range), use Calendar inline ou monte seu próprio DatePickerRange espelhando esse padrão.

Preview
Botão com placeholder até selecionar.

Anatomy

<DatePicker>
  └─ <Popover>
       ├─ <PopoverTrigger asChild>
       │    └─ <Button variant="outline">         ← mostra data ou placeholder
       └─ <PopoverContent>
            └─ <Calendar mode="single" autoFocus />
</DatePicker>

Usage

"use client";

import * as React from "react";
import { DatePicker } from "@kalvner/kds/forms/date-picker";

export function CheckoutDate() {
  const [date, setDate] = React.useState<Date>();
  return (
    <DatePicker
      value={date}
      onValueChange={setDate}
      placeholder="Quando você entrega?"
    />
  );
}

Props

PropTipoDefaultDescrição
valueDateData selecionada (controlada).
onValueChange(date: Date | undefined) => voidCallback.
placeholderstring'Selecione uma data'Texto antes da seleção.
disabledbooleanfalseBloqueia o trigger.
classNamestring'w-[240px]'Override no botão.

Para faixas e modos avançados, monte seu próprio composto usando Calendar + Popover diretamente.

Subcomponents

DatePicker não expõe subcomponentes — é um wrapper. Para customizar visualmente, use Calendar inline em Popover.

Variants

DatePicker é monolítico. Para variantes, prefira o composto à mão (troque o trigger por Input, ou Calendar por modo range).

States

EstadoComportamento
VazioBotão mostra placeholder em text-muted-foreground.
PreenchidoBotão mostra a data formatada (PP, ex: "May 9, 2026").
disabledBotão sem hover, opacity 50%.
AbertoPopover abre alinhado ao botão, foco no Calendar.

Composition

Para integrar com Form (RHF + zod):

<FormField
  control={form.control}
  name="dob"
  render={({ field }) => (
    <FormItem>
      <FormLabel>Data de nascimento</FormLabel>
      <FormControl>
        <DatePicker value={field.value} onValueChange={field.onChange} />
      </FormControl>
      <FormMessage />
    </FormItem>
  )}
/>

When to use

  • Forms com data única (cadastro, agendamento simples).
  • Filtros de "data específica" em dashboards.
  • Qualquer input de data em layout compacto.

When not to use

  • Faixas (de–até) — use Calendar mode="range" inline.
  • Múltiplas datas independentes — use Calendar mode="multiple".
  • Mobile sem espaço para Popover — prefira Drawer
    • Calendar inline.

Best practices

  • Use formato local. O default PP do date-fns adapta ao locale. Sem locale configurado, sai em inglês.
  • Placeholder descreve a função. "Quando você quer?" > "Data".
  • Para datas no passado, bloqueie via Calendar disabled={{ after: today }} — monte o composto à mão se precisar de controle fino.

Accessibility

ConcernComportamento
TriggerButton com aria-haspopup="dialog" (via Popover).
CalendarRecebe autoFocus ao abrir — foco no dia atual.
KeyboardSetas navegam pelo Calendar; Esc fecha o Popover.
LabelPareie com Label externamente — DatePicker não embute label.
LocaleConfigure no Calendar via locale para anúncios corretos.
  • Calendar — primitivo subjacente.
  • Popover — wrapper subjacente.
  • Drawer — alternativa mobile.
  • Form — integração com RHF + zod.

On this page