Date & Time/Calendar

Calendar

A date field component that allows users to enter and edit date.

Themed

When to Use

Use Calendar when you need to:

  • Let users pick a single date from a visual month grid
  • Select a date range such as check-in/check-out or start/end dates
  • Allow multiple individual date selections (e.g. availability)
  • Provide inline date selection as part of a larger form layout
  • Display a persistent calendar alongside other content

When Not to Use

  • Date input triggered by a button or field - use Date Picker which wraps Calendar in a Popover
  • Time-only selection - use a dedicated time picker component
  • Quick relative dates (today, last 7 days) - use preset buttons instead
  • Free-form date entry with keyboard - use a standard date input field

Default

Single date selection with dropdown month/year navigation.

April 2026

Range Selection

Select a date range across two side-by-side months. The selected range is visually highlighted between start and end dates.

April 2026
May 2026

Multiple Selection

Select multiple individual dates. Each click toggles a date on or off.

April 2026

Disabled Dates

Disable past dates or specific date matchers to restrict selection to valid options.

April 2026

UX & Design Guidelines

Selection Modes

Use mode="single" for simple date fields (appointments, birthdays). Use mode="range" with numberOfMonths={2} for booking flows so users see start and end in context. Use mode="multiple" sparingly - only when users genuinely need to pick several discrete dates.

Navigation & Layout

Use captionLayout="dropdown" when users may need to jump to distant months or years (e.g. date of birth). Use the default captionLayout="label" when navigation is typically within a few months of today. For range selection, display numberOfMonths={2} on desktop and fall back to a single month on mobile.

Responsive Behavior

The calendar grid uses --cell-size (defaults to 32px) for day cells. On mobile, ensure the calendar fits within the viewport width. Multi-month layouts stack vertically on narrow screens via flex-col md:flex-row. When placed inside a Popover, the calendar auto-positions to avoid overflow.

Timezone Handling

If users report off-by-one date selection (selecting the 20th highlights the 19th), set the timeZone prop to the user's local timezone using Intl.DateTimeFormat().resolvedOptions().timeZone. This ensures the calendar interprets midnight boundaries correctly across timezones.

Accessibility

Keyboard Navigation

  • Arrow Left / Arrow Right — Move focus to the previous/next day
  • Arrow Up / Arrow Down — Move focus to the same day in the previous/next week
  • Page Up / Page Down — Navigate to the previous/next month
  • Home / End — Jump to the start/end of the current week
  • Enter or Space — Select the focused date

Screen Reader Support

  • Built on React DayPicker which provides full ARIA grid semantics
  • Each day cell is announced with its full date and selection state
  • Month/year navigation announces the new visible month
  • Disabled dates are announced as unavailable via aria-disabled
  • Use aria-label on the calendar to provide context (e.g. "Select departure date")

Focus Management

Visible focus ring with 3px width using ring-ring/50 and ring-[3px]. Focus is automatically moved to the selected or focused day cell. When navigating months, focus transfers to the same day number in the new month (or the last available day if the month is shorter).

Touch Targets

Day cells are sized via --cell-size (default 32px) with aspect-square to maintain consistent hit areas. Navigation arrows use the same cell size for their touch target. For touch-heavy interfaces, increase the cell size via CSS custom property overrides.

ARIA Attributes

{/* Calendar with accessible label */}
<Calendar
  mode="single"
  selected={date}
  onSelect={setDate}
  aria-label="Select a date"
/>

{/* Disabled dates with screen reader context */}
<Calendar
  mode="single"
  selected={date}
  onSelect={setDate}
  disabled={(d) => d < new Date()}
  aria-describedby="date-constraint"
/>
<span id="date-constraint" className="sr-only">
  Only future dates can be selected
</span>

{/* Range calendar with descriptive label */}
<Calendar
  mode="range"
  selected={dateRange}
  onSelect={setDateRange}
  numberOfMonths={2}
  aria-label="Select check-in and check-out dates"
/>

API Reference

The Calendar component accepts the following props in addition to standard React DayPicker attributes.

PropTypeDefaultDescription
mode"single" | "multiple" | "range""single"The selection mode of the calendar.
selectedDate | Date[] | DateRange | undefinedThe selected date(s) based on mode.
onSelect(date: ...) => voidEvent handler called when a date is selected.
defaultMonthDateThe month to display initially.
numberOfMonthsnumber1Number of months to display side by side.
captionLayout"label" | "dropdown" | "dropdown-months" | "dropdown-years""label"Layout of the month/year caption navigation.
disabledMatcher | Matcher[]Dates that should be disabled and non-selectable.
showOutsideDaysbooleantrueShow days from previous/next months in the grid.
showWeekNumberbooleanfalseShow ISO week numbers in the first column.
timeZonestringIANA timezone for date display and selection (e.g. 'America/New_York').
buttonVariant"default" | "outline" | "ghost" | "destructive" | "secondary" | "link""ghost"The variant applied to the previous/next navigation buttons.
classNamestringAdditional CSS classes for styling the calendar container.