Date & time
Date range
Two dates, inclusive at both ends, with consumer-defined presets beside the calendar. LUC hard-codes no business windows: “last 7 days” is a preset you pass in, not a feature of the component.
Examples
Presets and a calendar
Presets are a typed list of label plus value (or a factory that receives today). The active preset is derived from the value — never a second piece of state that can drift.
Choose a preset, type the dates, or pick a range in the calendar.
value: 2026-09-01 → 2026-09-26
<Field label="Reporting period" description="Choose a preset, type the dates, or pick a range in the calendar.">
<DateRangePicker
value={range}
onValueChange={setRange}
todayValue={DEMO_TODAY}
presets={RANGE_PRESETS}
locale="en-US"
months={2}
/>
</Field>A range for a record, not a filter
No presets, no Today action, one visible month. A booking or a reporting period is a decision, not a browsing aid.
Billing runs on the first working day after the end date.
A same-day range is allowed; 21–24 September is not.
<DateRangePicker
value={invoiced}
onValueChange={setInvoiced}
todayValue={DEMO_TODAY}
months={1}
showTodayAction={false}
locale="en-US"
/>Sizes and states
The same shell as every other control: hover steps one border, focus draws the ring, invalid is negative without a red banner.
Default
Empty
Overlaps the locked audit window
Invalid
Disabled
Small
One month
the mobile layout
<DateRangePicker aria-label="Default range" locale="en-US" months={1} defaultValue={DEMO_RANGE} />
<DateRangePicker aria-label="Empty range" locale="en-US" months={1} />
<Field label="Period" error="Overlaps the locked audit window">
<DateRangePicker locale="en-US" months={1} defaultValue={DEMO_RANGE} />
</Field>
<DateRangePicker aria-label="Disabled range" locale="en-US" months={1} disabled defaultValue={DEMO_RANGE} />
<DateRangePicker aria-label="Small range" locale="en-US" months={1} size="sm" defaultValue={DEMO_RANGE} />Any preset shape, no business logic
A preset can be a fixed range or a factory. This one shows what a consumer-owned “rolling” window looks like — the calculation lives in the page, not in the component.
Both presets are computed in the page from the injected today.
const presets = [
{ id: "trailing", label: "Trailing 90 days", range: ({ today }) => ({ start: today.subtract({ days: 89 }), end: today }) },
];
<DateRangePicker value={range} onValueChange={setRange} presets={presets} todayValue={DEMO_TODAY} />Usage
import { DateRangePicker } from "@luc/ui";<DateRangePicker
aria-label="Reporting period"
value={range}
onValueChange={setRange}
todayValue={today}
months={2}
/>`value` is `{ start, end }` with both ends inclusive, or `null` when either end is missing. Pass `todayValue` so a screenshot, a test or a server render does not change meaning at midnight.
API
Read from the published TypeScript API, so a prop that is not listed here does not exist and a default that is listed is the one the compiler sees.
DateRangePicker shares its module with DatePicker, so the exports table below is the shared one; its own props table comes first, and the rest of the module is folded underneath it.
| Export | Kind | Signature |
|---|---|---|
DateField | 60 documented props | <T extends DateValue = DateValue>({ size, invalid, disabled, readOnly, className, trailingAction, ...props }: DateFieldProps<T>) => import("@types/react").JSX.Element |
DatePicker | 60 documented props | <T extends DateValue = DateValue>({ onValueChange, size, invalid, disabled, readOnly, required, locale, viewSwitch, showTodayAction, showClearAction, calendarButtonLabel, footer, className, todayValu… |
DateRangePicker | 60 documented props | <T extends DateValue = DateValue>({ onValueChange, size, invalid, disabled, readOnly, required, locale, months, presets, showTodayAction, showClearAction, calendarButtonLabel, footer, className, toda… |
DateRangePicker props
Type: DateRangePickerProps<T>
Values the compiler reads from the declaration.
| Prop | Type | Default | Notes |
|---|---|---|---|
allowsNonContiguousRanges?inherited | boolean | undefined | — | When combined with `isDateUnavailable`, determines whether non-contiguous ranges, i.e. ranges containing unavailable dates, may be selected. |
aria-describedby?inherited | string | undefined | — | Identifies the element (or elements) that describes the object. |
aria-details?inherited | string | undefined | — | Identifies the element (or elements) that provide a detailed, extended description for the object. |
aria-label?inherited | string | undefined | — | Defines a string value that labels the current element. |
aria-labelledby?inherited | string | undefined | — | Identifies the element (or elements) that labels the current element. |
autoFocus?inherited | boolean | undefined | — | Whether the element should receive focus on render. |
calendarButtonLabel? | string | undefined | — | |
className? | string | undefined | — | |
defaultOpen?inherited | boolean | undefined | — | Whether the overlay is open by default (uncontrolled). |
defaultValue?inherited | RangeValue<T> | null | undefined | — | The default value (uncontrolled). |
dir?inherited | string | undefined | — | |
disabled? | boolean | undefined | — | |
firstDayOfWeek?inherited | "sun" | "mon" | "tue" | "wed" | "thu" | "fri" | "sat" | undefined | — | The day that starts the week. |
footer? | ReactNode | — | |
form?inherited | string | undefined | — | The `<form>` element to associate the input with. The value of this attribute must be the id of a `<form>` in the same document. See [MDN](https://developer.mozilla.org/en-US/docs… |
granularity?inherited | Granularity | undefined | — | Determines the smallest unit that is displayed in the date picker. By default, this is `"day"` for dates, and `"minute"` for times. |
hidden?inherited | boolean | undefined | — | |
hideTimeZone?inherited | boolean | undefined | | Whether to hide the time zone abbreviation. |
hourCycle?inherited | 24 | 12 | undefined | — | Whether to display the time in 12 or 24 hour format. By default, this is determined by the user's locale. |
id?inherited | string | undefined | — | The element's unique identifier. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/id). |
inert?inherited | boolean | undefined | — | |
invalid? | boolean | undefined | — | |
isDateUnavailable?inherited | ((date: DateValue, anchorDate: CalendarDate | null) => boolean) | undefined | — | Callback that is called for each date of the calendar. If it returns true, then the date is unavailable. |
isOpen?inherited | boolean | undefined | — | Whether the overlay is open by default (controlled). |
lang?inherited | string | undefined | — | |
locale? | string | undefined | — | |
maxValue?inherited | DateValue | null | undefined | — | The maximum allowed date that a user may select. |
minValue?inherited | DateValue | null | undefined | — | The minimum allowed date that a user may select. |
months? | 1 | 2 | undefined | — | Months shown at once. Default `2`; the caller drops to 1 on mobile. |
onAnimationEnd?inherited | AnimationEventHandler<HTMLDivElement> | undefined | — | |
onAnimationEndCapture?inherited | AnimationEventHandler<HTMLDivElement> | undefined | — | |
onAnimationIteration?inherited | AnimationEventHandler<HTMLDivElement> | undefined | — | |
onAnimationIterationCapture?inherited | AnimationEventHandler<HTMLDivElement> | undefined | — | |
onAnimationStart?inherited | AnimationEventHandler<HTMLDivElement> | undefined | — | |
onAnimationStartCapture?inherited | AnimationEventHandler<HTMLDivElement> | undefined | — | |
onAuxClick?inherited | MouseEventHandler<HTMLDivElement> | undefined | — | |
onAuxClickCapture?inherited | MouseEventHandler<HTMLDivElement> | undefined | — | |
onBlur?inherited | ((e: FocusEvent<Element, Element>) => void) | undefined | — | Handler that is called when the element loses focus. |
onClick?inherited | MouseEventHandler<HTMLDivElement> | undefined | — | |
onClickCapture?inherited | MouseEventHandler<HTMLDivElement> | undefined | — | |
onContextMenu?inherited | MouseEventHandler<HTMLDivElement> | undefined | — | |
onContextMenuCapture?inherited | MouseEventHandler<HTMLDivElement> | undefined | — | |
onDoubleClick?inherited | MouseEventHandler<HTMLDivElement> | undefined | — | |
onDoubleClickCapture?inherited | MouseEventHandler<HTMLDivElement> | undefined | — | |
onFocus?inherited | ((e: FocusEvent<Element, Element>) => void) | undefined | — | Handler that is called when the element receives focus. |
onFocusChange?inherited | ((isFocused: boolean) => void) | undefined | — | Handler that is called when the element's focus status changes. |
onGotPointerCapture?inherited | PointerEventHandler<HTMLDivElement> | undefined | — | |
onGotPointerCaptureCapture?inherited | PointerEventHandler<HTMLDivElement> | undefined | — | |
onKeyDown?inherited | ((e: KeyboardEvent) => void) | undefined | — | Handler that is called when a key is pressed. |
onKeyUp?inherited | ((e: KeyboardEvent) => void) | undefined | — | Handler that is called when a key is released. |
onLostPointerCapture?inherited | PointerEventHandler<HTMLDivElement> | undefined | — | |
onLostPointerCaptureCapture?inherited | PointerEventHandler<HTMLDivElement> | undefined | — | |
onMouseDown?inherited | MouseEventHandler<HTMLDivElement> | undefined | — | |
onMouseDownCapture?inherited | MouseEventHandler<HTMLDivElement> | undefined | — | |
onMouseEnter?inherited | MouseEventHandler<HTMLDivElement> | undefined | — | |
onMouseLeave?inherited | MouseEventHandler<HTMLDivElement> | undefined | — | |
onMouseMove?inherited | MouseEventHandler<HTMLDivElement> | undefined | — | |
onMouseMoveCapture?inherited | MouseEventHandler<HTMLDivElement> | undefined | — | |
onMouseOut?inherited | MouseEventHandler<HTMLDivElement> | undefined | — | |
onMouseOutCapture?inherited | MouseEventHandler<HTMLDivElement> | undefined | — |
DateField props60 props
DateField props
Type: DateFieldProps<T>
Values the compiler reads from the declaration.
| Prop | Type | Default | Notes |
|---|---|---|---|
aria-describedby?inherited | string | undefined | — | Identifies the element (or elements) that describes the object. |
aria-details?inherited | string | undefined | — | Identifies the element (or elements) that provide a detailed, extended description for the object. |
aria-label?inherited | string | undefined | — | Defines a string value that labels the current element. |
aria-labelledby?inherited | string | undefined | — | Identifies the element (or elements) that labels the current element. |
autoComplete?inherited | string | undefined | — | Describes the type of autocomplete functionality the input should provide if any. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#htmlattrdefautocomplete… |
autoFocus?inherited | boolean | undefined | — | Whether the element should receive focus on render. |
className? | string | undefined | — | |
defaultValue?inherited | T | null | undefined | — | The default value (uncontrolled). |
dir?inherited | string | undefined | — | |
disabled? | boolean | undefined | — | |
form?inherited | string | undefined | — | The `<form>` element to associate the input with. The value of this attribute must be the id of a `<form>` in the same document. See [MDN](https://developer.mozilla.org/en-US/docs… |
granularity?inherited | Granularity | undefined | — | Determines the smallest unit that is displayed in the date picker. By default, this is `"day"` for dates, and `"minute"` for times. |
hidden?inherited | boolean | undefined | — | |
hideTimeZone?inherited | boolean | undefined | | Whether to hide the time zone abbreviation. |
hourCycle?inherited | 24 | 12 | undefined | — | Whether to display the time in 12 or 24 hour format. By default, this is determined by the user's locale. |
id?inherited | string | undefined | — | The element's unique identifier. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/id). |
inert?inherited | boolean | undefined | — | |
invalid? | boolean | undefined | — | |
isDateUnavailable?inherited | ((date: DateValue) => boolean) | undefined | — | Callback that is called for each date of the calendar. If it returns true, then the date is unavailable. |
isRequired?inherited | boolean | undefined | — | Whether user input is required on the input before form submission. |
lang?inherited | string | undefined | — | |
locale? | string | undefined | — | BCP-47 locale for segment order, weekday names and the visible month. |
maxValue?inherited | DateValue | null | undefined | — | The maximum allowed date that a user may select. |
minValue?inherited | DateValue | null | undefined | — | The minimum allowed date that a user may select. |
name?inherited | string | undefined | — | The name of the input element, used when submitting an HTML form. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#htmlattrdefname). |
onAnimationEnd?inherited | AnimationEventHandler<HTMLDivElement> | undefined | — | |
onAnimationEndCapture?inherited | AnimationEventHandler<HTMLDivElement> | undefined | — | |
onAnimationIteration?inherited | AnimationEventHandler<HTMLDivElement> | undefined | — | |
onAnimationIterationCapture?inherited | AnimationEventHandler<HTMLDivElement> | undefined | — | |
onAnimationStart?inherited | AnimationEventHandler<HTMLDivElement> | undefined | — | |
onAnimationStartCapture?inherited | AnimationEventHandler<HTMLDivElement> | undefined | — | |
onAuxClick?inherited | MouseEventHandler<HTMLDivElement> | undefined | — | |
onAuxClickCapture?inherited | MouseEventHandler<HTMLDivElement> | undefined | — | |
onBlur?inherited | ((e: FocusEvent<Element, Element>) => void) | undefined | — | Handler that is called when the element loses focus. |
onChange?inherited | ((value: MappedDateValue<T> | null) => void) | undefined | — | Handler that is called when the value changes. |
onClick?inherited | MouseEventHandler<HTMLDivElement> | undefined | — | |
onClickCapture?inherited | MouseEventHandler<HTMLDivElement> | undefined | — | |
onContextMenu?inherited | MouseEventHandler<HTMLDivElement> | undefined | — | |
onContextMenuCapture?inherited | MouseEventHandler<HTMLDivElement> | undefined | — | |
onDoubleClick?inherited | MouseEventHandler<HTMLDivElement> | undefined | — | |
onDoubleClickCapture?inherited | MouseEventHandler<HTMLDivElement> | undefined | — | |
onFocus?inherited | ((e: FocusEvent<Element, Element>) => void) | undefined | — | Handler that is called when the element receives focus. |
onFocusChange?inherited | ((isFocused: boolean) => void) | undefined | — | Handler that is called when the element's focus status changes. |
onGotPointerCapture?inherited | PointerEventHandler<HTMLDivElement> | undefined | — | |
onGotPointerCaptureCapture?inherited | PointerEventHandler<HTMLDivElement> | undefined | — | |
onKeyDown?inherited | ((e: KeyboardEvent) => void) | undefined | — | Handler that is called when a key is pressed. |
onKeyUp?inherited | ((e: KeyboardEvent) => void) | undefined | — | Handler that is called when a key is released. |
onLostPointerCapture?inherited | PointerEventHandler<HTMLDivElement> | undefined | — | |
onLostPointerCaptureCapture?inherited | PointerEventHandler<HTMLDivElement> | undefined | — | |
onMouseDown?inherited | MouseEventHandler<HTMLDivElement> | undefined | — | |
onMouseDownCapture?inherited | MouseEventHandler<HTMLDivElement> | undefined | — | |
onMouseEnter?inherited | MouseEventHandler<HTMLDivElement> | undefined | — | |
onMouseLeave?inherited | MouseEventHandler<HTMLDivElement> | undefined | — | |
onMouseMove?inherited | MouseEventHandler<HTMLDivElement> | undefined | — | |
onMouseMoveCapture?inherited | MouseEventHandler<HTMLDivElement> | undefined | — | |
onMouseOut?inherited | MouseEventHandler<HTMLDivElement> | undefined | — | |
onMouseOutCapture?inherited | MouseEventHandler<HTMLDivElement> | undefined | — | |
onMouseOver?inherited | MouseEventHandler<HTMLDivElement> | undefined | — | |
onMouseOverCapture?inherited | MouseEventHandler<HTMLDivElement> | undefined | — | |
onMouseUp?inherited | MouseEventHandler<HTMLDivElement> | undefined | — |
DatePicker props60 props
DatePicker props
Type: DatePickerProps<T>
Values the compiler reads from the declaration.
| Prop | Type | Default | Notes |
|---|---|---|---|
aria-describedby?inherited | string | undefined | — | Identifies the element (or elements) that describes the object. |
aria-details?inherited | string | undefined | — | Identifies the element (or elements) that provide a detailed, extended description for the object. |
aria-label?inherited | string | undefined | — | Defines a string value that labels the current element. |
aria-labelledby?inherited | string | undefined | — | Identifies the element (or elements) that labels the current element. |
autoComplete?inherited | string | undefined | — | Describes the type of autocomplete functionality the input should provide if any. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#htmlattrdefautocomplete… |
autoFocus?inherited | boolean | undefined | — | Whether the element should receive focus on render. |
calendarButtonLabel? | string | undefined | — | Accessible name for the calendar button. Localized by React Aria by default. |
className? | string | undefined | — | |
defaultOpen?inherited | boolean | undefined | — | Whether the overlay is open by default (uncontrolled). |
defaultValue?inherited | T | null | undefined | — | The default value (uncontrolled). |
dir?inherited | string | undefined | — | |
disabled? | boolean | undefined | — | |
firstDayOfWeek?inherited | "sun" | "mon" | "tue" | "wed" | "thu" | "fri" | "sat" | undefined | — | The day that starts the week. |
footer? | ReactNode | — | Extra footer content beside the quick actions. |
form?inherited | string | undefined | — | The `<form>` element to associate the input with. The value of this attribute must be the id of a `<form>` in the same document. See [MDN](https://developer.mozilla.org/en-US/docs… |
granularity?inherited | Granularity | undefined | — | Determines the smallest unit that is displayed in the date picker. By default, this is `"day"` for dates, and `"minute"` for times. |
hidden?inherited | boolean | undefined | — | |
hideTimeZone?inherited | boolean | undefined | | Whether to hide the time zone abbreviation. |
hourCycle?inherited | 24 | 12 | undefined | — | Whether to display the time in 12 or 24 hour format. By default, this is determined by the user's locale. |
id?inherited | string | undefined | — | The element's unique identifier. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/id). |
inert?inherited | boolean | undefined | — | |
invalid? | boolean | undefined | — | |
isDateUnavailable?inherited | ((date: DateValue) => boolean) | undefined | — | Callback that is called for each date of the calendar. If it returns true, then the date is unavailable. |
isOpen?inherited | boolean | undefined | — | Whether the overlay is open by default (controlled). |
lang?inherited | string | undefined | — | |
locale? | string | undefined | — | |
maxValue?inherited | DateValue | null | undefined | — | The maximum allowed date that a user may select. |
minValue?inherited | DateValue | null | undefined | — | The minimum allowed date that a user may select. |
name?inherited | string | undefined | — | The name of the input element, used when submitting an HTML form. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#htmlattrdefname). |
onAnimationEnd?inherited | AnimationEventHandler<HTMLDivElement> | undefined | — | |
onAnimationEndCapture?inherited | AnimationEventHandler<HTMLDivElement> | undefined | — | |
onAnimationIteration?inherited | AnimationEventHandler<HTMLDivElement> | undefined | — | |
onAnimationIterationCapture?inherited | AnimationEventHandler<HTMLDivElement> | undefined | — | |
onAnimationStart?inherited | AnimationEventHandler<HTMLDivElement> | undefined | — | |
onAnimationStartCapture?inherited | AnimationEventHandler<HTMLDivElement> | undefined | — | |
onAuxClick?inherited | MouseEventHandler<HTMLDivElement> | undefined | — | |
onAuxClickCapture?inherited | MouseEventHandler<HTMLDivElement> | undefined | — | |
onBlur?inherited | ((e: FocusEvent<Element, Element>) => void) | undefined | — | Handler that is called when the element loses focus. |
onClick?inherited | MouseEventHandler<HTMLDivElement> | undefined | — | |
onClickCapture?inherited | MouseEventHandler<HTMLDivElement> | undefined | — | |
onContextMenu?inherited | MouseEventHandler<HTMLDivElement> | undefined | — | |
onContextMenuCapture?inherited | MouseEventHandler<HTMLDivElement> | undefined | — | |
onDoubleClick?inherited | MouseEventHandler<HTMLDivElement> | undefined | — | |
onDoubleClickCapture?inherited | MouseEventHandler<HTMLDivElement> | undefined | — | |
onFocus?inherited | ((e: FocusEvent<Element, Element>) => void) | undefined | — | Handler that is called when the element receives focus. |
onFocusChange?inherited | ((isFocused: boolean) => void) | undefined | — | Handler that is called when the element's focus status changes. |
onGotPointerCapture?inherited | PointerEventHandler<HTMLDivElement> | undefined | — | |
onGotPointerCaptureCapture?inherited | PointerEventHandler<HTMLDivElement> | undefined | — | |
onKeyDown?inherited | ((e: KeyboardEvent) => void) | undefined | — | Handler that is called when a key is pressed. |
onKeyUp?inherited | ((e: KeyboardEvent) => void) | undefined | — | Handler that is called when a key is released. |
onLostPointerCapture?inherited | PointerEventHandler<HTMLDivElement> | undefined | — | |
onLostPointerCaptureCapture?inherited | PointerEventHandler<HTMLDivElement> | undefined | — | |
onMouseDown?inherited | MouseEventHandler<HTMLDivElement> | undefined | — | |
onMouseDownCapture?inherited | MouseEventHandler<HTMLDivElement> | undefined | — | |
onMouseEnter?inherited | MouseEventHandler<HTMLDivElement> | undefined | — | |
onMouseLeave?inherited | MouseEventHandler<HTMLDivElement> | undefined | — | |
onMouseMove?inherited | MouseEventHandler<HTMLDivElement> | undefined | — | |
onMouseMoveCapture?inherited | MouseEventHandler<HTMLDivElement> | undefined | — | |
onMouseOut?inherited | MouseEventHandler<HTMLDivElement> | undefined | — | |
onMouseOutCapture?inherited | MouseEventHandler<HTMLDivElement> | undefined | — |
Guidelines
Do
- Pass the business windows in as `presets`. A range component that knew what “quarter to date” meant would have to know what a quarter is, which is the consumer's domain.
- Read the selected range from `value` rather than mirroring it in a second state — an active preset is derived from the range, and two copies of the same fact drift.
- Use `DateRangePicker` when the two ends belong to one decision (a reporting period, a booking); use two `DatePicker`s when they are independent fields.
Don't
- Sending a range to a query as two instants. `09-01 → 09-18` is a pair of dates; whether the end day includes its last second is a query decision, and `.endOf("day")` belongs at the boundary, not in the control.
- Showing a range picker where a single date is what the user is choosing — two calendars for one decision is four times the surface and the same answer.
Accessibility: the two ends are one field group with a labelled start and end segment, so a keyboard user moves through six segments in reading order and a screen reader announces which end is focused; `isDateUnavailable` keeps blocked days focusable and announced rather than removing them from the grid.