Capítulo 32 de 108

Calendar

Core Idea

Componente de calendário para seleção de uma data ou intervalo de datas, construído sobre React DayPicker; base para date pickers e agendamento.

Key Concepts

  • mode: "single" (uma data) ou "range" (intervalo, usa DateRange com from/to).
  • selected / onSelect: par controlado; em mode="range" o selected é { from, to }.
  • captionLayout: "label" (padrão, texto estático) ou "dropdown" (dropdowns de mês/ano).
  • timeZone: garante que datas exibidas/selecionadas respeitem o fuso local do usuário; detectar com Intl.DateTimeFormat().resolvedOptions().timeZone dentro de useEffect (nunca no render, para evitar mismatch de hidratação SSR).
  • numberOfMonths: quantidade de meses exibidos lado a lado (comum em range picker: 2).
  • disabled: aceita array de Date para bloquear datas específicas (ex: datas já reservadas).
  • modifiers / modifiersClassNames: define estados customizados (ex: booked) e classes CSS associadas.
  • --cell-size: variável CSS que controla o tamanho das células do calendário, sobrescrevível via className ([--cell-size:--spacing(10)]) e responsiva por breakpoint.
  • showWeekNumber: exibe coluna com número da semana.
  • fixedWeeks: mantém a grade com número fixo de semanas (evita "pulos" de altura ao trocar de mês).
  • locale: prop de localização do DayPicker (ex: enUS, arSA, he de react-day-picker/locale), usada junto com dir para RTL.
  • DayButton / CalendarDayButton: componente exportado para customizar a renderização de cada dia (ex: adicionar preço abaixo do número).
  • Calendário Persa/Hijri/Jalali: trocar o import de react-day-picker por react-day-picker/persian dentro de calendar.tsx.

Code Examples

const [date, setDate] = React.useState<Date | undefined>(new Date())

<Calendar
  mode="single"
  selected={date}
  onSelect={setDate}
  className="rounded-lg border"
  captionLayout="dropdown"
/>
  • O que demonstra: uso básico single-date com dropdown de mês/ano.
const [dateRange, setDateRange] = React.useState<DateRange | undefined>({
  from: new Date(new Date().getFullYear(), 0, 12),
  to: addDays(new Date(new Date().getFullYear(), 0, 12), 30),
})

<Calendar
  mode="range"
  defaultMonth={dateRange?.from}
  selected={dateRange}
  onSelect={setDateRange}
  numberOfMonths={2}
/>
  • O que demonstra: range calendar com dois meses visíveis simultaneamente.
<Calendar
  mode="single"
  selected={date}
  onSelect={setDate}
  disabled={bookedDates}
  modifiers={{ booked: bookedDates }}
  modifiersClassNames={{ booked: "[&>button]:line-through opacity-100" }}
/>
  • O que demonstra: bloquear e estilizar datas já reservadas via disabled + modifiers.
- import { DayPicker } from "react-day-picker"
+ import { DayPicker } from "react-day-picker/persian"
  • O que demonstra: troca de import para habilitar calendário Persa/Hijri/Jalali (o resto do componente é reaproveitado).

Reference Tables

PropTipo/ValoresUso
mode"single" | "range"modo de seleção
captionLayout"label" | "dropdown"layout do cabeçalho de mês/ano
timeZonestring (IANA)fuso horário para exibição/seleção
numberOfMonthsnumbermeses exibidos lado a lado
showWeekNumberbooleanmostra número da semana
fixedWeeksbooleangrade com altura fixa
localeLocale (react-day-picker)localização de texto/formatos
dir"ltr" | "rtl"direção para RTL

Anti-patterns

  • Detectar timezone durante o render: causa hydration mismatch entre servidor e cliente; sempre detectar dentro de useEffect.
  • Ignorar o offset de data ao não passar timeZone: sintoma clássico é selecionar dia 20 e o calendário destacar dia 19; corrigir passando timeZone do usuário.
  • Usar classes direcionais fixas (rounded-l/r) em vez de lógicas (rounded-s/e) quando há suporte a RTL: quebra o layout em idiomas RTL.

Key Takeaways

  1. Calendar não tem lógica própria de data: é uma casca estilizada sobre React DayPicker, então a doc oficial do DayPicker é a referência definitiva de props/API.
  2. --cell-size é o principal hook de customização visual (tamanho de célula), responsivo via classes Tailwind arbitrárias.
  3. Suporte a calendários não-gregorianos (Persa/Hijri) é feito trocando apenas o import da lib, sem reescrever o componente.
  4. Migração de versões antigas do componente requer adicionar locale manualmente em vários pontos (Calendar, CalendarDayButton, formatters) — não é automático.
  5. disabled + modifiers/modifiersClassNames é o padrão para estados customizados de dia (reservado, feriado, etc.), não apenas para bloqueio simples.

Connects To

  • Date Picker: combina Calendar com Popover para criar um seletor de data compacto.
  • Button: Calendar depende do componente Button internamente (ChevronLeft/Right, dia selecionado).
  • Field / Card / InputGroup: usados em composições de presets, seletor de data+hora, e range picker.