Skip to content

Inputs

Date picker

A calendar for picking a single date or a range, inline or in a popover under a field-style trigger. The month grid is fully keyboard navigable, ranges preview as you hover, and min, max and custom rules disable dates that can't be booked.

On this page

October 2026

MoTuWeThFrSaSu

November 2026

MoTuWeThFrSaSu

Oct 21 – Oct 24 · 3 nights

Usage

components/ui/date-picker.tsx
import { DatePicker } from "@/components/ui/date-picker";import { Field } from "@/components/ui/field"; export function Example() {  return (    <Field label="Due date">      <DatePicker defaultValue={new Date(2026, 9, 30)} />    </Field>  );}

Examples

Date range

Two months side by side (stacked on phones). The first click sets the start, the second the end; hover previews the range.

October 2026

MoTuWeThFrSaSu

November 2026

MoTuWeThFrSaSu

Oct 21 – Oct 24 · 3 nights

Popover trigger

DatePicker looks like the other fields and opens the calendar under it. It closes on select, Escape or a click outside.

Clients see this on the invoice.

Single date

Today is marked with a dot. Use the arrow keys to move, Page Up and Page Down to change month.

October 2026

MoTuWeThFrSaSu

Disabled dates

min and max bound the selection; isDateDisabled rules out anything else, here weekends.

October 2026

MoTuWeThFrSaSu

Props

DatePicker

  • mode"single" | "range"default: "single"Pick one date or a from–to range.
  • value / defaultValueDate | null · DateRangedefault: —Controlled or initial value. A range is { from, to }.
  • onValueChange(value) => voiddefault: —Called with the new date or range.
  • placeholderstringdefault: "Pick a date"Trigger text while empty.
  • size"sm" | "md" | "lg"default: "md"Trigger height 32 / 36 / 40px.
  • align"start" | "end"default: "start"Popover edge aligned with the trigger.
  • formatOptionsIntl.DateTimeFormatOptionsdefault: { month: "short", day: "numeric", year: "numeric" }How the trigger shows the value.
  • invalid / disabledbooleandefault: —Set automatically inside a Field with error or disabled.
  • ...calendar propsmin, max, isDateDisabled, weekStartsOn, numberOfMonths, today, localedefault: —Passed to the Calendar inside.

Calendar

  • mode"single" | "range"default: "single"Selection mode.
  • value / defaultValueDate | null · DateRangedefault: —Controlled or initial selection.
  • onValueChange(value) => voiddefault: —Called on every pick.
  • numberOfMonths1 | 2default: 1Months shown side by side.
  • defaultMonthDatedefault: —First visible month. Defaults to the selection, then today.
  • weekStartsOn0 | 1default: 1Sunday (0) or Monday (1).
  • min / maxDatedefault: —Earliest and latest selectable date.
  • isDateDisabled(date: Date) => booleandefault: —Disable any other dates.
  • todayDatedefault: —Override today (read on the client by default).
  • localestringdefault: "en-US"Month and weekday names via Intl.

Accessibility

  • Each month is a role="grid" labelled by its caption; the caption is a polite live region, so month changes are announced.
  • One day is in the tab order. Arrow keys move by day and week, Home and End to the start and end of the week, Page Up and Page Down by month, with Shift by year.
  • Day buttons have full labels (“Friday, October 23, 2026”), today has aria-current="date", and selected cells have aria-selected.
  • Disabled dates stay focusable with aria-disabled, so keyboard users can move past them, but they can't be picked.
  • The trigger has aria-haspopup="dialog" and aria-expanded; the popover is a labelled dialog, Escape closes it and focus returns to the trigger.

Suggested