Date Range Picker
Edit and select a start and end date.
Teammates see you as away on these dates.
Installation
pnpm dlx shadcn@4.18.0 add @siteplane/date-range-pickerComplete the one-time setup first. Registry JSON lists source files and dependencies.
For this page’s examples, also install:
pnpm dlx shadcn@4.18.0 add @siteplane/button @siteplane/form @siteplane/inputField is installed with Input.
Usage
import { DateRangePicker } from "@/siteplane/components/date-range-picker";
<DateRangePicker aria-label="Trip dates" />;Controlled value
Pass value and onValueChange to keep the range in React state. The control reports complete ranges and undefined when cleared; store null for an empty controlled value, because undefined makes the picker uncontrolled.
Unavailable dates
Use calendarProps.disabled for dates that can't be booked and endMonth for the booking window. The calendar doesn't offer these dates, and a typed date that breaks a rule marks the range invalid once it loses focus or the form is submitted; FieldError shows the message. Check the range again on the server.
Bookings open up to six months ahead.
Disabled, read-only and invalid
A disabled Field also disables the range, and readOnly shows a range that can't be changed on the regular field surface. For an error from your application, set invalid on Field and explain the problem in a FieldError.
Set by your plan.
Submission and reset
Set startName and endName to submit two hidden YYYY-MM-DD strings; the example submits { "departureDate": "2026-11-02", "returnDate": "2026-11-06" }. An empty endpoint submits an empty string, and there is no single name or range object. Changing locale changes only the display. With required, submitting an incomplete range is blocked, the field is focused and FieldError shows the required message. Native form reset restores defaultValue; reset controlled state yourself.
API reference
| Prop | Type | Default | Description |
|---|---|---|---|
aria-label | string | unset | Accessible name when no FieldLabel or aria-labelledby names the range. |
aria-labelledby / aria-describedby | string | unset | External label and help ids; inside a Field, FieldLabel, FieldDescription and FieldError are connected automatically. |
aria-invalid | AriaAttributes[aria-invalid] | unset | External invalid state; while set, it replaces the built-in date checks. |
value / default | DateRange | null (value only) | uncontrolled / unset | Controlled or initial range; null is an empty controlled value. |
on | (value: DateRange | undefined) => void | unset | Reports a complete range, or undefined when cleared. |
disabled | boolean | false | Prevents editing/opening; a disabled Field also disables the range. |
class | string | unset | Outer control styling. |
locale | string | context | Formatting locale, not time zone. |
calendar | CalendarOptions | unset | The calendar options below: defaultMonth, disabled, startMonth, endMonth and todayDate. |
read | boolean | false | Read-only field on the regular surface; required blocks form submission until both dates are set, focuses the field and shows the required message in FieldError. |
size | sm | md | lg | xl | provider / lg | Control size. |
text | sm | base | unset | Field text size; unset is 14px, or 16px at xl, like Input. |
variant | default | elevated | inset | soft | default | Input surface. |
form | string | unset | Associated form ID. |
start | string | unset | Names of the two hidden serialized date fields. |
start | string | localized Start Date / End Date | Accessible names of the start and end date inputs. Screen readers announce each date segment with this name and the range label. |
open | string | Open date range calendar | Calendar button name. |
icon | action-end | none | action-end | action-end ends the field with the button that opens the calendar; none leaves the range to typing, for a range beside a calendar of its own. |
incomplete | string | Enter a complete date range. | The error of a required picker while its range is incomplete, shown by FieldError. |
size and variant use the same scale and surfaces as Input; see Input sizes and variants.
Calendar options
calendarProps takes CalendarOptions, the type of the same options on Calendar. startMonth and endMonth (Date, unset) limit the calendar to the first and last allowed months. disabled (unset) makes days unavailable with one matcher or a list of matchers, each a Date, a (date: Date) => boolean test or a rule with after, before, from, to and dayOfWeek (0 Sunday through 6 Saturday); true disables the whole calendar. Both apply to picking in the calendar and to typed dates.
defaultMonth (Date, unset) sets the month the calendar shows when it opens; while it is set, it also wins over the month of the selected range. todayDate (Date, the device's date) sets the day the calendar marks as today; without a selected range, the calendar opens on its month, and typed segments start from it.
Exported types: DateRangePickerProps, DateRange. These describe the contracts above.
Usage notes
Values use native Date calendar fields in the local runtime time zone. Locale changes formatting, not the zone. DateRange is {from?:Date,to?:Date}; the control commits a complete range. Inside a Field, FieldLabel names DateRangePicker and clicking it focuses the first segment; outside a Field, pass aria-label or aria-labelledby. Arrow keys change the focused date segment. Only the props listed above are supported, and DateRangePicker renders its own segments, calendar button and popover, the last two only with iconMode="action-end"; it accepts no children or ref. The named Props type and value type are exported from the component module.
The start date, the dash and the end date read in the direction of the locale, which the arrow keys follow too, and are isolated from the text around them. An en-US range stays 01/01/2024 – 10/14/2026 in a right-to-left page, while the field keeps the page's direction: its calendar button sits at the page's inline end.