Date Picker
The date picker lets users select a single date, multiple dates, or a date range from a calendar, with day, month, and year views.
import {DatePicker} from "@qualcomm-ui/react/date-picker"Overview
- The value is an array of
DateValuefrom @internationalized/date, not a nativeDate. The type is re-exported from@qualcomm-ui/react/date-picker. - Build values with
parseDate("2026-08-14")for fixed dates, ortoday(getLocalTimeZone())for relative ones. Both return aCalendarDate, a date with no time attached. - To keep a time alongside the date, start from a
CalendarDateTimeorZonedDateTimeinstead. Picking a new day preserves the time. - Avoid converting a native
Date. Only its local year, month, and day are read, so a UTC timestamp such asnew Date("2026-08-14T00:00:00Z")becomes August 13 in time zones behind UTC. Pass the ISO date string toparseDateinstead.
Examples
Single Date
The default selectionMode. Type a date into the field in the locale format, or pick one from the calendar.
<DatePicker className="w-64" label="Departure date" />
Composite
Build with the composite API for granular control. The simple API DatePicker renders exactly this tree, including the three DatePicker.View blocks for the day, month, and year views.
<DatePicker.Root
className="w-64"
invalid={!value.length}
onValueChange={(details) => setValue(details.value)}
required
value={value}
>
<DatePicker.Control>
<DatePicker.InputGroup label="Departure date" />
</DatePicker.Control>
<DatePicker.Hint>Choose a date in mm/dd/yyyy format</DatePicker.Hint>
<DatePicker.ErrorText>A departure date is required</DatePicker.ErrorText>
<Portal>
<DatePicker.Positioner>
<DatePicker.Content>
<DatePicker.View view="day">
<DatePicker.ViewControl>
<DatePicker.ViewTrigger view="month">
<DatePicker.MonthText />
</DatePicker.ViewTrigger>
<DatePicker.ViewTrigger view="year">
<DatePicker.YearText />
</DatePicker.ViewTrigger>
<DatePicker.PrevTrigger />
<DatePicker.NextTrigger />
</DatePicker.ViewControl>
<DatePicker.Table>
<DatePicker.DayGridHeader />
<DatePicker.DayGrid />
</DatePicker.Table>
</DatePicker.View>
<DatePicker.View view="month">
<DatePicker.ViewControl>
<DatePicker.ViewTrigger disabled view="month">
<DatePicker.MonthText />
</DatePicker.ViewTrigger>
<DatePicker.ViewTrigger disabled view="year">
<DatePicker.YearText />
</DatePicker.ViewTrigger>
<DatePicker.PrevTrigger />
<DatePicker.NextTrigger />
<DatePicker.ViewCloseTrigger />
</DatePicker.ViewControl>
<DatePicker.Table>
<DatePicker.MonthGrid />
</DatePicker.Table>
</DatePicker.View>
<DatePicker.View view="year">
<DatePicker.ViewControl>
<DatePicker.ViewTrigger disabled view="month">
<DatePicker.MonthText />
</DatePicker.ViewTrigger>
<DatePicker.ViewTrigger disabled view="year">
<DatePicker.YearText />
</DatePicker.ViewTrigger>
<DatePicker.PrevTrigger />
<DatePicker.NextTrigger />
<DatePicker.ViewCloseTrigger />
</DatePicker.ViewControl>
<DatePicker.Table>
<DatePicker.YearGrid />
</DatePicker.Table>
</DatePicker.View>
</DatePicker.Content>
</DatePicker.Positioner>
</Portal>
</DatePicker.Root>
Range
Set selectionMode="range" to collect a start and end date. Use the separator prop on DatePicker.InputGroup to change the character between the two inputs; it defaults to -. The calendar shows a band between the two dates.
A range can be partially filled, in which case the missing end is null.
<DatePicker className="w-80" label="Trip dates" selectionMode="range" />
Multiple
Set selectionMode="multiple" to collect several dates, shown as dismissible tags in the field. The field is display-only in this mode, so dates are picked from the calendar rather than typed.
Use maxSelectedDates to cap how many dates can be selected.
The popover always shows action buttons in this mode.
<DatePicker
className="w-80"
label="Maintenance days"
maxSelectedDates={4}
selectionMode="multiple"
/>
Action Buttons
Set closeOnSelect to false to add a footer with Cancel and OK buttons. selectionMode="multiple" always includes it.
Selections apply as they are made. OK keeps them and closes the popover, while Cancel, Escape, and clicking outside all revert to the value the popover opened with. The field's clear button applies immediately and is not affected by Cancel.
<DatePicker className="w-64" closeOnSelect={false} label="Departure date" />
Open on Click
Set openOnClick to automatically open the popover when the user clicks the field. This keeps focus in it so typing continues.
<DatePicker className="w-64" label="Departure date" openOnClick />
Presets
Use the presets prop to offer common selections, such as the last 7 days. A button in the day view header opens the presets panel.
Each preset is a {label, value} pair, where value is either a named range such as "next7Days" or an explicit DateValue[].
import type {ReactElement} from "react"
import {DatePicker, type DatePickerPreset} from "@qualcomm-ui/react/date-picker"
const presets: DatePickerPreset[] = [
{label: "Next 7 days", value: "next7Days"},
{label: "Next 14 days", value: "next14Days"},
{label: "Next 30 days", value: "next30Days"},
{label: "Next 90 days", value: "next90Days"},
{label: "Next week", value: "nextWeek"},
{label: "Next month", value: "nextMonth"},
{label: "Next quarter", value: "nextQuarter"},
{label: "Next year", value: "nextYear"},
]
export function DatePickerPresetsDemo(): ReactElement {
return (
<DatePicker
className="w-80"
label="Date range"
presets={presets}
selectionMode="range"
/>
)
}Sizes
This component supports three size options to accommodate different layout densities.
The available sizes are sm, md, and lg. The default size is md. Size applies to the input field only; the calendar is unaffected.
<DatePicker className="w-64" label="Small" size="sm" />
<DatePicker className="w-64" label="Medium" size="md" />
<DatePicker className="w-64" label="Large" size="lg" />
Hint and Error Text
Add a hint to provide additional context below the field. When invalid is true, the errorText replaces it and the field shows an error indicator icon.
<DatePicker
className="w-64"
hint="Choose a date in mm/dd/yyyy format"
label="Departure date"
/>
<DatePicker
className="w-64"
errorText="A departure date is required"
hint="Choose a date in mm/dd/yyyy format"
invalid
label="Departure date"
/>
States
The date picker supports disabled, read-only, and invalid states.
<DatePicker
className="w-64"
defaultValue={departureDate}
disabled
label="Disabled"
/>
<DatePicker
className="w-64"
defaultValue={departureDate}
label="Read only"
readOnly
/>
<DatePicker
className="w-64"
defaultValue={departureDate}
errorText="Choose a later date"
invalid
label="Invalid"
/>
Min and Max Dates
Use the min and max props to bound the selectable dates. Dates outside the bounds are disabled, and typed values are clamped into range.
<DatePicker
className="w-64"
hint="Within the next 30 days"
label="Departure date"
max={now.add({days: 30})}
min={now}
/>
Outside Days
Days from the previous and next month fill the first and last week of the grid. Set hideOutsideDays to leave those cells empty instead.
| S | M | T | W | T | F | S |
|---|---|---|---|---|---|---|
26 | 27 | 28 | 29 | 30 | 31 | 1 |
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 | 31 | 1 | 2 | 3 | 4 | 5 |
Jan | Feb | Mar | Apr |
May | Jun | Jul | Aug |
Sep | Oct | Nov | Dec |
2020 | 2021 | 2022 | 2023 |
2024 | 2025 | 2026 | 2027 |
2028 | 2029 |
<DatePicker hideOutsideDays variant="inline" />
Unavailable Dates
Use the isDateUnavailable prop to block individual dates that min and max cannot express, such as weekends or holidays.
<DatePicker
className="w-64"
hint="Weekends are not available"
isDateUnavailable={isWeekend}
label="Delivery date"
/>
Locale
Use the locale prop to change how dates are displayed and parsed. It takes a BCP 47 language tag and defaults to en-US. The month and weekday names, the first day of the week, the placeholder, and the separators the field accepts all follow from it. For example, de-DE gives a dd.mm.yyyy placeholder and accepts . as the separator.
Use the startOfWeek prop to override only the first day of the week.
<DatePicker className="w-64" label="Departure date" locale={locale} />
Controlled State
Set the initial value using the defaultValue prop, or use value and onValueChange to control the value manually. These props follow our controlled state pattern.
The value is always an array, and entries can be null when a range is partially filled.
[]
<DatePicker
className="w-80"
label="Trip dates"
onValueChange={(details) => setValue(details.value)}
selectionMode="range"
value={value}
/>
Inline
Set variant to inline to render an always-visible calendar with no field or popover. This variant never shows action buttons and has no inputs, so it does not submit a value with a native form; read the selection through value and onValueChange.
The inline variant shows a headline with the label and current value. Set headline to false to remove it. Use moreLabel and rangePlaceholder to customize it.
| S | M | T | W | T | F | S |
|---|---|---|---|---|---|---|
26 | 27 | 28 | 29 | 30 | 31 | 1 |
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 | 31 | 1 | 2 | 3 | 4 | 5 |
Jan | Feb | Mar | Apr |
May | Jun | Jul | Aug |
Sep | Oct | Nov | Dec |
2020 | 2021 | 2022 | 2023 |
2024 | 2025 | 2026 | 2027 |
2028 | 2029 |
| S | M | T | W | T | F | S |
|---|---|---|---|---|---|---|
26 | 27 | 28 | 29 | 30 | 31 | 1 |
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 | 31 | 1 | 2 | 3 | 4 | 5 |
Jan | Feb | Mar | Apr |
May | Jun | Jul | Aug |
Sep | Oct | Nov | Dec |
2020 | 2021 | 2022 | 2023 |
2024 | 2025 | 2026 | 2027 |
2028 | 2029 |
<DatePicker variant="inline" />
<DatePicker headline={false} variant="inline" />
Custom Trigger
DatePicker.Context is a render prop that hands you the picker api, so you can drive your own presentation from the picker's state. Use it to read the current value, format your own label, or call actions such as clearValue.
<DatePicker.Context>
{(api) => <span>{api.valueAsString[0] || "No date selected"}</span>}
</DatePicker.Context>DatePicker.Trigger pairs with it to replace the field entirely. Pass render to supply your own element; it renders a plain <button> otherwise. Place it inside DatePicker.Control, which anchors the popover.
<DatePicker.Context>
{(api) => (
<DatePicker.Trigger render={<Button variant="outline" />}>
{api.valueAsString[0] || "Pick a date"}
</DatePicker.Trigger>
)}
</DatePicker.Context>Accessibility attributes, focus restoration, and dismissal behavior come from the picker, so you do not write them yourself.
<DatePicker.Root closeOnSelect={false}>
<DatePicker.Context>
{(api) => (
<DatePicker.Control className="flex gap-2">
<DatePicker.Trigger render={<Button variant="outline" />}>
{api.valueAsString[0] || "Pick a date"}
</DatePicker.Trigger>
{api.value.length ? (
<Button
onClick={() => api.clearValue()}
type="button"
variant="ghost"
>
Clear
</Button>
) : null}
</DatePicker.Control>
)}
</DatePicker.Context>
<Portal>
<DatePicker.Positioner>
<DatePicker.Content>
<DatePicker.Headline>
<DatePicker.HeadlineLabel />
<DatePicker.HeadlineValue />
</DatePicker.Headline>
<DatePicker.View view="day">
<DatePicker.ViewControl>
<DatePicker.ViewTrigger view="month">
<DatePicker.MonthText />
</DatePicker.ViewTrigger>
<DatePicker.ViewTrigger view="year">
<DatePicker.YearText />
</DatePicker.ViewTrigger>
<DatePicker.PrevTrigger />
<DatePicker.NextTrigger />
</DatePicker.ViewControl>
<DatePicker.Table>
<DatePicker.DayGridHeader />
<DatePicker.DayGrid />
</DatePicker.Table>
</DatePicker.View>
<DatePicker.View view="month">
<DatePicker.ViewControl>
<DatePicker.ViewTrigger disabled view="month">
<DatePicker.MonthText />
</DatePicker.ViewTrigger>
<DatePicker.ViewTrigger disabled view="year">
<DatePicker.YearText />
</DatePicker.ViewTrigger>
<DatePicker.PrevTrigger />
<DatePicker.NextTrigger />
<DatePicker.ViewCloseTrigger />
</DatePicker.ViewControl>
<DatePicker.Table>
<DatePicker.MonthGrid />
</DatePicker.Table>
</DatePicker.View>
<DatePicker.View view="year">
<DatePicker.ViewControl>
<DatePicker.ViewTrigger disabled view="month">
<DatePicker.MonthText />
</DatePicker.ViewTrigger>
<DatePicker.ViewTrigger disabled view="year">
<DatePicker.YearText />
</DatePicker.ViewTrigger>
<DatePicker.PrevTrigger />
<DatePicker.NextTrigger />
<DatePicker.ViewCloseTrigger />
</DatePicker.ViewControl>
<DatePicker.Table>
<DatePicker.YearGrid />
</DatePicker.Table>
</DatePicker.View>
<DatePicker.Actions>
<DatePicker.CancelTrigger />
<DatePicker.OkTrigger />
</DatePicker.Actions>
</DatePicker.Content>
</DatePicker.Positioner>
</Portal>
</DatePicker.Root>
Within Dialog
Set portalProps to {disabled: true} to render the calendar popover in place rather than at the end of document.body. This is required inside a Dialog or Popover.
import type {ReactElement} from "react"
import {Button} from "@qualcomm-ui/react/button"
import {DatePicker} from "@qualcomm-ui/react/date-picker"
import {Dialog} from "@qualcomm-ui/react/dialog"
export function DatePickerWithinDialogDemo(): ReactElement {
return (
<Dialog.Root>
<Dialog.Trigger>
<Button emphasis="primary" variant="fill">
Open Dialog
</Button>
</Dialog.Trigger>
<Dialog.FloatingPortal>
<Dialog.Body>
<Dialog.Heading>Book a Flight</Dialog.Heading>
<Dialog.CloseButton />
<DatePicker
className="w-64"
label="Departure date"
portalProps={{disabled: true}}
/>
</Dialog.Body>
<Dialog.Footer>
<Dialog.CloseTrigger>
<Button emphasis="primary" size="sm" variant="fill">
Confirm
</Button>
</Dialog.CloseTrigger>
</Dialog.Footer>
</Dialog.FloatingPortal>
</Dialog.Root>
)
}Forms
Choose the form library that fits your needs—we've built examples with React Hook Form and Tanstack Form to get you started.
The selection is submitted under name, and the number of entries follows the selection mode: one for a single date, two for a range, and one per date in multiple mode. Entries arrive in document order, so a range is always start then end.
A range keeps the position of each end, so clearing only the start submits an empty first entry and the end date second. Read a range by position rather than by taking the first non-empty entry.
Resetting the form restores the initial value.
React Hook Form
Use React Hook Form to handle the input state and validation. ArkType works great for schema validation if you need it.
import type {ReactElement} from "react"
import {type} from "arktype"
import {Controller, type SubmitHandler, useForm} from "react-hook-form"
import type {DateValue} from "@qualcomm-ui/core/date-picker"
import {Button} from "@qualcomm-ui/react/button"
import {DatePicker} from "@qualcomm-ui/react/date-picker"
import {createToaster, Toaster} from "@qualcomm-ui/react/toast"
const valueSchema = type({
departureDate: type("unknown[] > 0").configure({
message: "A departure date is required",
}),
})
type ValueSchema = typeof valueSchema.infer
const toaster = createToaster({
overlap: true,
placement: "bottom-end",
})
export function DatePickerHookFormDemo(): ReactElement {
const {
control,
formState: {isSubmitting},
handleSubmit,
setError,
} = useForm<ValueSchema>({
defaultValues: {
departureDate: [],
},
})
const handleFormSubmit: SubmitHandler<ValueSchema> = (data) => {
const validation = valueSchema(data)
if (validation instanceof type.errors) {
for (const error of validation) {
const field = error.path?.[0] as keyof ValueSchema
if (field) {
setError(field, {
message: error.message,
})
}
}
return
}
toaster.create({
label: "Form submitted",
type: "success",
})
}
return (
<>
<Toaster toaster={toaster} />
<form
className="flex w-64 flex-col gap-4"
noValidate
onSubmit={(event) => void handleSubmit(handleFormSubmit)(event)}
>
<Controller
control={control}
name="departureDate"
render={({
field: {onChange, value, ...fieldProps},
fieldState: {error},
}) => (
<DatePicker
errorText={error?.message}
hint="Choose a date in mm/dd/yyyy format"
invalid={!!error}
label="Departure date"
onValueChange={(details) => onChange(details.value)}
required
value={value as DateValue[]}
{...fieldProps}
/>
)}
/>
<div className="flex w-full justify-end">
<Button
disabled={isSubmitting}
emphasis="primary"
type="submit"
variant="fill"
>
Submit
</Button>
</div>
</form>
</>
)
}Tanstack Form
Tanstack Form handles validation with its built-in validators.
import type {ReactElement} from "react"
import {useForm} from "@tanstack/react-form"
import {Button} from "@qualcomm-ui/react/button"
import {DatePicker, type DateValue} from "@qualcomm-ui/react/date-picker"
import {createToaster, Toaster} from "@qualcomm-ui/react/toast"
const toaster = createToaster({
overlap: true,
placement: "bottom-end",
})
export function DatePickerTanstackFormDemo(): ReactElement {
const form = useForm({
defaultValues: {
departureDate: [] as (DateValue | null)[],
},
onSubmit: () => {
toaster.create({
label: "Form submitted",
type: "success",
})
},
})
return (
<>
<Toaster toaster={toaster} />
<form
className="w-64"
noValidate
onSubmit={(event) => {
event.preventDefault()
event.stopPropagation()
void form.handleSubmit()
}}
>
<form.Field
name="departureDate"
validators={{
onChange: ({value}) =>
value.length === 0 ? "A departure date is required" : undefined,
}}
>
{(field) => (
<DatePicker
className="w-full"
errorText={field.state.meta.errors[0]}
hint="Choose a date in mm/dd/yyyy format"
invalid={field.state.meta.errors.length > 0}
label="Departure date"
onValueChange={(details) => field.handleChange(details.value)}
required
value={field.state.value}
/>
)}
</form.Field>
<div className="mt-2 flex w-full justify-end">
<Button
disabled={form.state.isSubmitting}
emphasis="primary"
type="submit"
variant="fill"
>
Submit
</Button>
</div>
</form>
</>
)
}Explorer
| S | M | T | W | T | F | S |
|---|---|---|---|---|---|---|
26 | 27 | 28 | 29 | 30 | 31 | 1 |
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 | 31 | 1 | 2 | 3 | 4 | 5 |
Jan | Feb | Mar | Apr |
May | Jun | Jul | Aug |
Sep | Oct | Nov | Dec |
2020 | 2021 | 2022 | 2023 |
2024 | 2025 | 2026 | 2027 |
2028 | 2029 |
Component Anatomy
Hover to highlight, click to view API
API
<DatePicker>
The flattened date picker extends the DatePicker.Root component with the following props:
Omit<
DatePickerActionsProps,
'children'
>
Omit<
DatePickerContentProps,
'children'
>
Omit<
DatePickerControlProps,
'children'
>
booleaninline variant.Omit<
DatePickerHeadlineProps,
'children'
>
inline variant.inline
variant.stringPortalPropsOmit<
DatePickerPositionerProps,
'children'
>
Array<{
label: ReactNode
value:
| Array<DateValue>
| 'thisWeek'
| 'lastWeek'
| 'nextWeek'
| 'thisMonth'
| 'lastMonth'
| 'nextMonth'
| 'thisQuarter'
| 'lastQuarter'
| 'nextQuarter'
| 'thisYear'
| 'lastYear'
| 'nextYear'
| 'last3Days'
| 'last7Days'
| 'last14Days'
| 'last30Days'
| 'last90Days'
| 'next3Days'
| 'next7Days'
| 'next14Days'
| 'next30Days'
| 'next90Days'
}>
Omit<
DatePickerPresetsProps,
'children'
>
| 'input'
| 'inline'
-
input - a labelled field that opens the calendar in a popover.-
inline - an always-visible, flat calendar that commits on selection.Composite API
This section describes the elements of the DatePicker's composite API.
<DatePicker.Root>
<div> element by default.booleanmultiple.(
identifier: CalendarIdentifier,
) => Calendar
locale.import {createCalendar} from "@internationalized/date"
const props = {createCalendar, locale: "fa-IR"}
DateValuebooleanArray<DateValue>
| 'day'
| 'month'
| 'year'
'ltr' | 'rtl'
booleanbooleanDateValue(
date: DateValue,
details: {
locale: string
timeZone: string
},
) => string
booleanbooleanbooleanboolean(
date: DateValue,
locale: string,
) => boolean
booleanstringDateValuenumberselectionMode is multiple.| 'day'
| 'month'
| 'year'
DateValue| 'day'
| 'month'
| 'year'
stringname attribute of the input element.VoidFunction(details: {
focusedValue: DateValue
value: Array<DateValue>
valueAsString: string[]
view:
| 'day'
| 'month'
| 'year'
}) => void
(details: {
open: boolean
value: Array<DateValue>
}) => void
(details: {
value: Array<DateValue>
valueAsString: string[]
view:
| 'day'
| 'month'
| 'year'
}) => void
(details: {
view:
| 'day'
| 'month'
| 'year'
}) => void
(details: {
view:
| 'day'
| 'month'
| 'year'
visibleRange: {
end: DateValue
start: DateValue
}
}) => void
booleanbooleanboolean(
value: string,
details: {
locale: string
timeZone: string
},
) => DateValue
stringbooleanboolean| ReactElement
| ((
props: object,
) => ReactElement)
boolean| 'single'
| 'multiple'
| 'range'
-
single - only one date can be selected-
multiple - multiple dates can be selected-
range - a range of dates can be selected| 'sm'
| 'md'
| 'lg'
booleannumber0 - Sunday
1 - Monday
2 - Tuesday
3 - Wednesday
4 - Thursday
5 - Friday
6 - Saturdaystring{
clearTrigger?: string
content?: string
dayCell?: (state: {
disabled: boolean
firstInHoveredRange: boolean
firstInRange: boolean
focused: boolean
inHoveredRange: boolean
inRange: boolean
invalid: boolean
lastInHoveredRange: boolean
lastInRange: boolean
outsideRange: boolean
selectable: boolean
selected: boolean
today: boolean
unavailable: boolean
value: DateValue
valueText: string
weekend: boolean
}) => string
errorIndicator?: string
inputDescription?: (
format: string,
) => string
nextTrigger?: (
view:
| 'day'
| 'month'
| 'year',
) => string
placeholder?: (
locale: string,
) => {
day: string
month: string
year: string
}
presetsTrigger?: (
open: boolean,
) => string
presetTrigger?: (
value: string[],
) => string
prevTrigger?: (
view:
| 'day'
| 'month'
| 'year',
) => string
rangeInputEnd?: string
rangeInputStart?: string
trigger?: (state: {
open: boolean
selectionMode:
| 'single'
| 'multiple'
| 'range'
valueText: string[]
}) => string
viewCloseTrigger?: string
viewTrigger?: (
view:
| 'day'
| 'month'
| 'year',
targetView?:
| 'day'
| 'month'
| 'year',
) => string
}
booleanArray<DateValue>
| 'day'
| 'month'
| 'year'
| 'previous'
| 'min'
= year → month → day
className'qui-date-picker__root'data-date-picker-part'root'data-disableddata-emptydata-hide-outside-daysdata-readonlydata-state| 'open'
| 'closed'
<DatePicker.Label>
<label> element by default.number| ReactElement
| ((
props: object,
) => ReactElement)
className'qui-input__label qui-date-picker__label'data-date-picker-part'label'data-disableddata-readonlydata-size| 'sm'
| 'md'
| 'lg'
data-state| 'open'
| 'closed'
<DatePicker.Control>
<div> element by default.| ReactElement
| ((
props: object,
) => ReactElement)
data-date-picker-part'control'data-disableddata-placeholder-shown<DatePicker.InputGroup>
See Shortcuts for the tree this renders in each selection mode.
(
dateText: string,
) => string
multiple mode.booleanstringstringmultiple mode.stringclassName'qui-input__input-group qui-date-picker__input-group'data-date-picker-part'input-group'data-disableddata-invaliddata-placeholder-showndata-placement| 'bottom'
| 'bottom-end'
| 'bottom-start'
| 'left'
| 'left-end'
| 'left-start'
| 'right'
| 'right-end'
| 'right-start'
| 'top'
| 'top-end'
| 'top-start'
data-readonlydata-side| 'top'
| 'right'
| 'bottom'
| 'left'
data-size| 'sm'
| 'md'
| 'lg'
data-state| 'open'
| 'closed'
tabIndexnumber<DatePicker.Input>
A range picker renders two inputs, distinguished by index.
<input> element by default.booleannumber| ReactElement
| ((
props: object,
) => ReactElement)
className'qui-input__input qui-date-picker__input'data-date-picker-part'input'data-indexnumberdata-invaliddata-placeholder-showndata-size| 'sm'
| 'md'
| 'lg'
data-state| 'open'
| 'closed'
<DatePicker.ValueTags>
multiple mode as dismissible tags. Renders a
visually-hidden input per selected date so the selection participates in form
submission under the picker's name.(
dateText: string,
) => string
stringclassName'qui-date-picker__value-tags'data-date-picker-part'hidden-input'data-indexnumberstyletabIndexnumber<DatePicker.ClearTrigger>
<button> element by default;
pass render to adopt your own element.<DatePicker.ClearTrigger render={<Button variant="ghost" />}>
Clear
</DatePicker.ClearTrigger>
| ReactElement
| ((
props: object,
) => ReactElement)
data-date-picker-part'clear-trigger'hiddenboolean<DatePicker.InputClearTrigger>
The styled clear trigger used inside DatePicker.InputGroup. Wraps DatePicker.ClearTrigger in a compact IconButton.
| ReactElement
| ((
props: object,
) => ReactElement)
<DatePicker.ErrorIndicator>
<span> element by default.| LucideIcon
| ReactNode
| ReactElement
| ((
props: object,
) => ReactElement)
className'qui-input__error-indicator'data-date-picker-part'error-indicator'data-size| 'sm'
| 'md'
| 'lg'
hiddenboolean<DatePicker.Trigger>
<button>
element by default; pass render to adopt your own element.<DatePicker.Trigger render={<Button variant="outline" />}>
Pick a date
</DatePicker.Trigger>
| ReactElement
| ((
props: object,
) => ReactElement)
data-date-picker-part'trigger'data-placeholder-showndata-placement| 'bottom'
| 'bottom-end'
| 'bottom-start'
| 'left'
| 'left-end'
| 'left-start'
| 'right'
| 'right-end'
| 'right-start'
| 'top'
| 'top-end'
| 'top-start'
data-side| 'top'
| 'right'
| 'bottom'
| 'left'
data-state| 'open'
| 'closed'
<DatePicker.InputTrigger>
The styled calendar trigger used inside DatePicker.InputGroup. Wraps DatePicker.Trigger in a compact IconButton.
| ReactElement
| ((
props: object,
) => ReactElement)
<DatePicker.InputIcon>
A non-interactive calendar icon. DatePicker.InputGroup renders it in place of DatePicker.InputTrigger in multiple mode, where the field itself carries the trigger bindings.
<DatePicker.Hint>
<div> element by default.| ReactElement
| ((
props: object,
) => ReactElement)
data-date-picker-part'hint'data-disabledhiddenboolean<DatePicker.ErrorText>
<div>
element by default.| ReactElement
| ((
props: object,
) => ReactElement)
data-date-picker-part'error-text'hiddenboolean<DatePicker.Positioner>
<div> element by
default.| ReactElement
| ((
props: object,
) => ReactElement)
data-date-picker-part'positioner'style<DatePicker.Content>
<div> element by default.| ReactElement
| ((
props: object,
) => ReactElement)
data-date-picker-part'content'data-inlinedata-placement| 'bottom'
| 'bottom-end'
| 'bottom-start'
| 'left'
| 'left-end'
| 'left-start'
| 'right'
| 'right-end'
| 'right-start'
| 'top'
| 'top-end'
| 'top-start'
data-presets-opendata-side| 'top'
| 'right'
| 'bottom'
| 'left'
data-state| 'open'
| 'closed'
hiddenbooleantabIndex-1
<DatePicker.Headline>
<div> element by default.| ReactElement
| ((
props: object,
) => ReactElement)
className'qui-date-picker__headline'data-date-picker-part'headline'<DatePicker.HeadlineLabel>
The default caption is Date range in range mode and Date otherwise. Pass children to override it.
<span>
element by default.| ReactElement
| ((
props: object,
) => ReactElement)
className'qui-date-picker__headline-label'data-date-picker-part'headline-label'<DatePicker.HeadlineValue>
In multiple mode this shows up to two dates then appends a count suffix.
<span> element
by default.DateTimeFormatOptions(
count: number,
) => string
multiple mode when more than two dates are selected.string[
string,
string,
]
| ReactElement
| ((
props: object,
) => ReactElement)
className'qui-date-picker__headline-value'data-date-picker-part'headline-value'<DatePicker.View>
<div>
element by default.| ReactElement
| ((
props: object,
) => ReactElement)
| 'day'
| 'month'
| 'year'
data-date-picker-part'view'data-view| 'day'
| 'month'
| 'year'
hiddenboolean<DatePicker.ViewControl>
<div> element by
default.| ReactElement
| ((
props: object,
) => ReactElement)
data-date-picker-part'view-control'data-view| 'day'
| 'month'
| 'year'
<DatePicker.ViewTrigger>
| ReactElement
| ((
props: object,
) => ReactElement)
| 'day'
| 'month'
| 'year'
data-date-picker-part'view-trigger'data-view| 'day'
| 'month'
| 'year'
<DatePicker.ViewCloseTrigger>
| ReactElement
| ((
props: object,
) => ReactElement)
data-date-picker-part'view-close-trigger'<DatePicker.PrevTrigger>
Disabled when the previous page falls entirely outside min.
| LucideIcon
| ReactNode
LucideIcon or a ReactElement.| ReactElement
| ((
props: object,
) => ReactElement)
| 'day'
| 'month'
| 'year'
data-date-picker-part'prev-trigger'data-disabled<DatePicker.NextTrigger>
Disabled when the next page falls entirely outside max.
| LucideIcon
| ReactNode
LucideIcon or a ReactElement.| ReactElement
| ((
props: object,
) => ReactElement)
| 'day'
| 'month'
| 'year'
data-date-picker-part'next-trigger'data-disabled<DatePicker.MonthText>
ViewTrigger that jumps to the month view.| 'numeric'
| 'short'
| 'long'
| '2-digit'
| 'narrow'
<DatePicker.YearText>
ViewTrigger
that jumps to the year view.| 'numeric'
| '2-digit'
<DatePicker.RangeText>
<div> element by default.| ReactElement
| ((
props: object,
) => ReactElement)
data-date-picker-part'range-text'<DatePicker.Table>
The column count is fixed per view.
<table> element by default.| ReactElement
| ((
props: object,
) => ReactElement)
data-columnsnumberdata-date-picker-part'table'data-view| 'day'
| 'month'
| 'year'
tabIndex-1
<DatePicker.TableHead>
<thead> element by default.| ReactElement
| ((
props: object,
) => ReactElement)
data-date-picker-part'table-head'data-disableddata-view| 'day'
| 'month'
| 'year'
<DatePicker.TableHeader>
<th> element by default.| ReactElement
| ((
props: object,
) => ReactElement)
data-date-picker-part'table-header'data-disableddata-view| 'day'
| 'month'
| 'year'
<DatePicker.TableBody>
<tbody> element by default.| ReactElement
| ((
props: object,
) => ReactElement)
data-date-picker-part'table-body'data-disableddata-view| 'day'
| 'month'
| 'year'
<DatePicker.TableRow>
<tr> element by default.| ReactElement
| ((
props: object,
) => ReactElement)
data-date-picker-part'table-row'data-disableddata-view| 'day'
| 'month'
| 'year'
<DatePicker.TableCell>
The bindings differ by the view the cell belongs to.
<td> element by default.| number
| DateValue
numberboolean| ReactElement
| ((
props: object,
) => ReactElement)
{
end: T
start: T
}
data-date-picker-part'table-cell'data-selecteddata-valuenumber<DatePicker.TableCellTrigger>
The bindings differ by the view the cell belongs to.
<div> element by
default.| ReactElement
| ((
props: object,
) => ReactElement)
data-date-picker-part'table-cell-trigger'data-disableddata-focusdata-hover-range-enddata-hover-range-startdata-in-hover-rangedata-in-rangedata-outside-rangedata-range-enddata-range-startdata-selectabledata-selecteddata-todaydata-unavailabledata-valuenumberdata-view'year'data-weekendtabIndex-1 | 0
<DatePicker.DayGridHeader>
| 'short'
| 'long'
| 'narrow'
<DatePicker.DayGrid>
<DatePicker.MonthGrid>
| 'short'
| 'long'
<DatePicker.YearGrid>
Renders the year cells for the year view. Takes no props.
<DatePicker.Presets>
<div> element by default.| ReactElement
| ((
props: object,
) => ReactElement)
data-date-picker-part'presets'hiddenboolean<DatePicker.PresetsTrigger>
| ReactElement
| ((
props: object,
) => ReactElement)
data-date-picker-part'presets-trigger'<DatePicker.PresetTrigger>
<button> element by default.| Array<DateValue>
| 'thisWeek'
| 'lastWeek'
| 'nextWeek'
| 'thisMonth'
| 'lastMonth'
| 'nextMonth'
| 'thisQuarter'
| 'lastQuarter'
| 'nextQuarter'
| 'thisYear'
| 'lastYear'
| 'nextYear'
| 'last3Days'
| 'last7Days'
| 'last14Days'
| 'last30Days'
| 'last90Days'
| 'next3Days'
| 'next7Days'
| 'next14Days'
| 'next30Days'
| 'next90Days'
| ReactElement
| ((
props: object,
) => ReactElement)
data-date-picker-part'preset-trigger'<DatePicker.Actions>
closeOnSelect is false. Renders a <div> element by default.| ReactElement
| ((
props: object,
) => ReactElement)
className'qui-date-picker__actions'data-date-picker-part'actions'<DatePicker.CancelTrigger>
| 'default'
| 'compact'
booleantrue, pointer/focus
events are blocked, and the component is visually dimmed.| 'neutral'
| 'primary'
| 'danger'
| 'white-persistent'
| 'black-persistent'
| 'inverse'
| LucideIcon
| ReactNode
LucideIcon, the size will automatically match the size prop.
Supply as a ReactElement for additional customization.| ReactElement
| ((
props: object,
) => ReactElement)
| 'sm'
| 'md'
| 'lg'
| LucideIcon
| ReactNode
LucideIcon,
the size will automatically match the size prop. Supply as a
ReactElement for additional customization.| 'fill'
| 'ghost'
| 'outline'
<DatePicker.OkTrigger>
| 'default'
| 'compact'
booleantrue, pointer/focus
events are blocked, and the component is visually dimmed.| 'neutral'
| 'primary'
| 'danger'
| 'white-persistent'
| 'black-persistent'
| 'inverse'
| LucideIcon
| ReactNode
LucideIcon, the size will automatically match the size prop.
Supply as a ReactElement for additional customization.| ReactElement
| ((
props: object,
) => ReactElement)
| 'sm'
| 'md'
| 'lg'
| LucideIcon
| ReactNode
LucideIcon,
the size will automatically match the size prop. Supply as a
ReactElement for additional customization.| 'fill'
| 'ghost'
| 'outline'
<DatePicker.Context>
DatePickerApi
The api handed to the DatePicker.Context render prop.
VoidFunction(options?: {
focus?: boolean
}) => void
booleanbooleanDateValueDatestring(
month: number,
) => void
(
year: number,
) => void
(
value: DateValue,
opts?: DateTimeFormatOptions,
) => string
(
week: number,
from?: DateValue,
) => Array<DateValue>
(props: {
disabled?: boolean
value: DateValue
visibleRange?: {
end: T
start: T
}
}) => {
disabled: boolean
firstInHoveredRange: boolean
firstInRange: boolean
focused: boolean
inHoveredRange: boolean
inRange: boolean
invalid: boolean
lastInHoveredRange: boolean
lastInRange: boolean
outsideRange: boolean
selectable: boolean
selected: boolean
today: boolean
unavailable: boolean
value: DateValue
valueText: string
weekend: boolean
}
() => {
end: T
start: T
}
(props?: {
format?: 'short' | 'long'
}) => Array<{
disabled?: boolean
label: string
value: number
}>
(props?: {
columns?: number
format?: 'short' | 'long'
}) => Array<
Array<{
disabled?: boolean
label: string
value: number
}>
>
(props: {
columns?: number
disabled?: boolean
value: number
}) => {
disabled: boolean
firstInHoveredRange: boolean
firstInRange: boolean
focused: boolean
inHoveredRange: boolean
inRange: boolean
lastInHoveredRange: boolean
lastInRange: boolean
outsideRange: boolean
selectable: boolean
selected: boolean
value: DateValue
valueText: string
}
(
from?: DateValue,
) => Array<Array<DateValue>>
(
duration: DateDuration,
) => {
visibleRange: {
end: T
start: T
}
visibleRangeText: {
end: string
start: string
}
weeks: Array<
Array<DateValue>
>
}
(
value:
| 'thisWeek'
| 'lastWeek'
| 'nextWeek'
| 'thisMonth'
| 'lastMonth'
| 'nextMonth'
| 'thisQuarter'
| 'lastQuarter'
| 'nextQuarter'
| 'thisYear'
| 'lastYear'
| 'nextYear'
| 'last3Days'
| 'last7Days'
| 'last14Days'
| 'last30Days'
| 'last90Days'
| 'next3Days'
| 'next7Days'
| 'next14Days'
| 'next30Days'
| 'next90Days',
) => Array<DateValue>
() => Array<{
disabled?: boolean
label: string
value: number
}>
(props?: {
columns?: number
}) => Array<
Array<{
disabled?: boolean
label: string
value: number
}>
>
(props: {
columns?: number
disabled?: boolean
value: number
}) => {
disabled: boolean
firstInHoveredRange: boolean
firstInRange: boolean
focused: boolean
inHoveredRange: boolean
inRange: boolean
lastInHoveredRange: boolean
lastInRange: boolean
outsideRange: boolean
selectable: boolean
selected: boolean
value: DateValue
valueText: string
}
VoidFunctionVoidFunctionbooleanbooleanboolean(
date: DateValue,
) => boolean
numbernumberbooleanbooleanboolean| 'single'
| 'multiple'
| 'range'
VoidFunction(
value: DateValue,
) => void
(
open: boolean,
) => void
(
time: {
hour?: number
millisecond?: number
minute?: number
second?: number
},
index?: number,
) => void
(
values: Array<DateValue>,
) => void
(
view:
| 'day'
| 'month'
| 'year',
) => void
(
value: DateValue,
) => void
Array<DateValue>
Array<Date>
string[]
| 'day'
| 'month'
| 'year'
{
end: T
start: T
}
{
end: string
formatted: string
start: string
}
Array<{
long: string
narrow: string
short: string
value: DateValue
}>
Array<Array<DateValue>>
Data Structures
DatePickerPositioningOptions
numberstring[data-menu-part=arrow]).() =>
| 'clippingAncestors'
| Element
| Array<Element>
| {
height: number
width: number
x: number
y: number
}
boolean| boolean
| Array<
| 'bottom'
| 'bottom-end'
| 'bottom-start'
| 'left'
| 'left-end'
| 'left-start'
| 'right'
| 'right-end'
| 'right-start'
| 'top'
| 'top-end'
| 'top-start'
>
(
element:
| HTMLElement
| VirtualElement,
) => {
height?: number
width?: number
x?: number
y?: number
}
numberboolean| boolean
| {
ancestorResize?: boolean
ancestorScroll?: boolean
animationFrame?: boolean
elementResize?: boolean
layoutShift?: boolean
}
{
crossAxis?: number
mainAxis?: number
}
(
data: ComputePositionReturn,
) => void
(data: {
placed: boolean
}) => void
numberboolean| 'bottom'
| 'bottom-end'
| 'bottom-start'
| 'left'
| 'left-end'
| 'left-start'
| 'right'
| 'right-end'
| 'right-start'
| 'top'
| 'top-end'
| 'top-start'
booleannumberboolean| 'absolute'
| 'fixed'
(data: {
updatePosition: () => Promise<void>
}) => void | Promise<void>
Shortcuts
<DatePicker.InputGroup>
Groups the field parts into one bordered control. For a single date picker it renders roughly this structure:
<DatePicker.Label>{label}</DatePicker.Label>
<div>
<DatePicker.Input index={0} />
<DatePicker.InputClearTrigger />
<span aria-hidden />
<DatePicker.ErrorIndicator />
<DatePicker.InputTrigger />
</div>DatePicker.InputClearTrigger and DatePicker.InputTrigger are the styled field triggers, each a compact IconButton wrapping DatePicker.ClearTrigger and DatePicker.Trigger. The empty span is the divider between the input and the triggers.
In range mode it renders two inputs with the separator between them:
<DatePicker.Input index={0} />
<span aria-hidden>{separator}</span>
<DatePicker.Input index={1} />In multiple mode it renders DatePicker.ValueTags in place of the inputs:
<DatePicker.ValueTags dismissLabel={dismissLabel} placeholder={placeholder} />Multiple mode also replaces DatePicker.InputTrigger with DatePicker.InputIcon, a non-interactive calendar icon, because the field itself carries the trigger bindings.
<DatePicker.DayGridHeader>
Renders the weekday header row of the day view. This shortcut is equivalent to:
<DatePicker.TableHead>
<DatePicker.TableRow>
{weekDays.map((weekDay, i) => (
<DatePicker.TableHeader key={i} aria-label={weekDay.long} scope="col">
{weekDay[format]}
</DatePicker.TableHeader>
))}
</DatePicker.TableRow>
</DatePicker.TableHead><DatePicker.DayGrid>
Renders the day cells of the visible month. This shortcut is equivalent to:
<DatePicker.TableBody>
{weeks.map((week, i) => (
<DatePicker.TableRow key={i}>
{week.map((day, idx) => (
<DatePicker.TableCell key={idx} value={day} visibleRange={visibleRange}>
<DatePicker.TableCellTrigger>{day.day}</DatePicker.TableCellTrigger>
</DatePicker.TableCell>
))}
</DatePicker.TableRow>
))}
</DatePicker.TableBody><DatePicker.MonthGrid>
Renders the month cells of the month view. This shortcut is equivalent to:
<DatePicker.TableBody>
{getMonthsGrid({columns, format}).map((months, row) => (
<DatePicker.TableRow key={row}>
{months.map((month, index) => (
<DatePicker.TableCell key={index} value={month.value}>
<DatePicker.TableCellTrigger>
{month.label}
</DatePicker.TableCellTrigger>
</DatePicker.TableCell>
))}
</DatePicker.TableRow>
))}
</DatePicker.TableBody><DatePicker.YearGrid>
Renders the year cells of the year view. This shortcut is equivalent to:
<DatePicker.TableBody>
{getYearsGrid({columns}).map((years, row) => (
<DatePicker.TableRow key={row}>
{years.map((year, index) => (
<DatePicker.TableCell key={index} value={year.value}>
<DatePicker.TableCellTrigger>{year.label}</DatePicker.TableCellTrigger>
</DatePicker.TableCell>
))}
</DatePicker.TableRow>
))}
</DatePicker.TableBody>
inlinecalendar. For finer control, compose the parts yourself with DatePicker.Root and friends.