Skip to content
Design System
Contact

Date picker

Single dates and ranges with presets, in a popover calendar.

Componentsreact-day-pickerPopover

Playground

The calendar inside every picker, shown inline so each prop is visible. Today is fixed to Sep 29, 2026. Use the arrow keys on a focused day to move by day and week.

Preview
September 2026

Sep 26 – Oct 3, 2026, 8 days

Props

Mode
Months
Caption
Week starts on
example.tsxtsx
1import { Calendar } from "@/components/ui/calendar"
2import type { DateRange } from "react-day-picker"
3
4const [range, setRange] = useState<DateRange | undefined>()
5
6<Calendar
7 mode="range"
8 selected={range}
9 onSelect={setRange}
10 today={new Date(2026, 8, 29)}
11/>

States

The trigger button in every state. Errors name the rule and the conflicting date, so the fix is obvious.

States
  • Kick-off date

    Weekdays only

    Defaultplaceholder
  • Kick-off date

    Weekdays only

    Hover:hover
  • Kick-off date

    Weekdays only

    Focus:focus-visible
  • Kick-off date

    Weekdays only

    Loadingaria-busy
  • Kick-off date

    Locked after the contract is signed

    Disableddisabled
  • Contract end

    End date must be after start date (Oct 19, 2026).

    Erroraria-invalid
  • Kick-off date

    Available, a Monday

    Successvalid pick

Examples

Working pickers in popovers: a single date with past days, weekends and anything beyond 90 days disabled; a range with presets (two months on desktop, one on phones); and paired start and end fields that validate each other.

Single date with disabled days and a 90-day limit

Weekdays only, from today to 90 days ahead.

Range with presets

Sep 23 – Sep 29, 2026, 7 days

Start and end with validation

End date must be after start date (Oct 19, 2026).

API

PropTypeDefaultDescription
mode"single" | "range"—Selection mode. Range returns { from, to } as a DateRange.
selected / onSelectDate | DateRange | undefined—Controlled selection. The picker closes on pick in single mode.
numberOfMonthsnumber1Months shown side by side on md+; they stack on phones. The range picker uses 2 on desktop, 1 on mobile.
disabledMatcher | Matcher[]—Days that cannot be picked, e.g. { before: today }, { after: max } or { dayOfWeek: [0, 6] }.
startMonth / endMonthDate—Navigation limits (min and max month). Required for the dropdown caption.
captionLayout"label" | "dropdown""label"Dropdowns jump across months and years for dates far from today.
weekStartsOn0 | 1 | … | 60First day of the week, usually taken from the user's locale.
showOutsideDaysbooleantrueShow trailing days from adjacent months to keep rows full.
todayDate—Overrides today for the today marker; pinned here to keep renders deterministic.

Accessibility

Keyboard

Open the picker or select the focused day
EnterorSpace
Previous or next day
←or→
Previous or next week
↑or↓
Previous or next month
Page UporPage Down
Start or end of the week
HomeorEnd
Close and return focus to the trigger
Esc

Semantics and ARIA

  • The trigger is a real button with a visible label; its text is the formatted date or the placeholder, so the current value is announced.
  • The clear button sits next to the trigger, never inside it, and says what it clears: aria-label="Clear date, Oct 5, 2026".
  • The calendar is a grid from react-day-picker; focus moves to the selected day (or today) when it opens, and disabled days are skipped and marked aria-disabled.
  • Invalid triggers set aria-invalid and aria-describedby pointing at the error text.
  • Range presets are buttons with aria-pressed, and the selected length is announced through a polite live region.