Date range picker
Let people choose start and end dates with a date range picker and calendar controls.
Examples
Mobile
320pxMobile Lg
480pxTablet
640pxDesktop
1024px| S | M | T | W | T | F | S |
|---|---|---|---|---|---|---|
Range endpoints
Use one DatePicker.Root with selectionMode="range". Group each input and trigger in a DatePicker.Control. Set index={0} on the start Input and Trigger and index={1} on the end Input and Trigger. There is no separate DateRangePicker export.
Give each endpoint its own visible label, format hint, and form name. The start cannot be after the end, and the end cannot be before the start. Root bounds further limit both fields and the shared calendar.
min and max use Date values; defaultValue is an array of dates. Create calendar dates with local year, month, and day values, such as new Date(2026, 8, 28) for September 28. onValueChange receives the selected Date values and their ISO strings in valueAsString. It preserves start and end slots, using undefined in value and an empty string in valueAsString for an unset endpoint. Selecting a date closes the calendar; use the other endpoint’s trigger to edit it. The visible fields use MM/DD/YYYY.
Component API
Use DatePicker with selectionMode="range". Set index={0} on the start Input and Trigger and index={1} on the end Input and Trigger. Both endpoints share one calendar. The visible fields use MM/DD/YYYY; callback valueAsString uses ISO YYYY-MM-DD.
Root<div>
Owns selected dates, bounds, and calendar state.
| Prop | Type | Description |
|---|---|---|
selectionMode | range (required for this pattern) | Enables range selection. |
defaultValue | (Date | undefined)[] | Initial uncontrolled selected dates. In range mode, index 0 is the start and index 1 is the end; either slot may be undefined. |
value | (Date | undefined)[] | Controlled selected dates. In range mode, index 0 is the start and index 1 is the end; either slot may be undefined. |
min | Date | Earliest selectable calendar date. |
max | Date | Latest selectable calendar date. |
onValueChange | ({ value: (Date | undefined)[]; valueAsString: string[]; view: day | month | year }) => void | Receives proposed dates, ISO YYYY-MM-DD strings, and the view. Unset range endpoints keep their slots as undefined and empty strings. Update value in the callback when controlling the selection. |
ids | Datepicker ElementIds | Overrides generated part IDs. Input, label, and trigger IDs use callbacks, such as input: index => index === 0 ? "start-date" : "end-date". |
defaultDate | Date | Initial navigation fallback when no date is selected. Does not select or submit a value. |
rangeAnchor | Date | Fixed peer date for range markers and preview; independent of the selected value. |
readOnly | boolean | Makes the visible inputs read-only and prevents calendar editing. |
required | boolean | Marks the visible inputs required. |
locale | string | Locale for month and weekday labels. Defaults to English. |
Control<div>
Groups each date input and calendar trigger.
Input<input>
Receives a typed MM/DD/YYYY start or end date. Each field sets aria-invalid for malformed text or a date outside its effective bounds.
| Prop | Type | Description |
|---|---|---|
index | 0 | 1 | Endpoint to edit or open: 0 for start, 1 for end. Use the same index on each input and its trigger. |
Trigger<button>
Opens the shared calendar for the indexed input.
| Prop | Type | Description |
|---|---|---|
index | 0 | 1 | Endpoint to edit or open: 0 for start, 1 for end. Use the same index on each input and its trigger. |
Content<div>
Place one calendar here for both range inputs.
View<div>
Shows day, month, or year selection.
| Prop | Type | Description |
|---|---|---|
view | day | month | year (required) | Active calendar view. |
TableCellTrigger<button>
Selects a date in the range.
| Prop | Type | Description |
|---|---|---|
value | Date | number (required) | Use a Date from api.weeks for a day, a zero-based month from api.months for a month, or a year from api.years for a year. |
| Attribute | Value | Purpose |
|---|---|---|
data-range-start | Present at the range start | Styles the range start. |
data-range-end | Present at the range end | Styles the range end. |
data-in-range | Present inside the range | Styles the active endpoint preview interval. |
Accessibility
Give the start and end fields distinct visible labels, names, and format hints. An end date cannot precede the start; a start date cannot follow the end. Root min and max further limit both endpoints.