Components · Date, time and scheduling
DateTimePicker
A date and a wall-clock time in one field: DatePicker plus a typed 12- or 24-hour time, a step and a time-zone slot.
Interview time with a time zone
Value: 2026-11-10T14:30
import { useState } from 'react';
import { Field, FieldLabel, FieldDescription } from '@rookcom/monarch-react';
import { DateTimePicker } from '@rookcom/monarch-react/scheduling';
const TODAY = '2026-11-04';
function Interview() {
const [value, setValue] = useState<string | null>('2026-11-10T14:30');
return (
<Field>
<FieldLabel>Interview</FieldLabel>
<DateTimePicker
locale="en-GB"
today={TODAY}
min="2026-11-04T09:00"
step={15}
timeZone="IST"
value={value}
onValueChange={setValue}
/>
<FieldDescription>Value: {value ?? 'none'}</FieldDescription>
</Field>
);
}
<Interview />Usage examples
12-hour clock (en-US) and sizes
import { Field, FieldLabel } from '@rookcom/monarch-react';
import { DateTimePicker } from '@rookcom/monarch-react/scheduling';
const TODAY = '2026-11-04';
<Field>
<FieldLabel>Send at</FieldLabel>
<DateTimePicker
locale="en-US"
today={TODAY}
defaultValue="2026-11-05T08:00"
timeZone="New York"
/>
</Field>
<DateTimePicker
aria-label="Reminder"
size="sm"
locale="en-GB"
today={TODAY}
defaultValue="2026-11-05T17:45"
/>Disabled
import { Field, FieldLabel } from '@rookcom/monarch-react';
import { DateTimePicker } from '@rookcom/monarch-react/scheduling';
const TODAY = '2026-11-04';
<Field disabled>
<FieldLabel>Starts</FieldLabel>
<DateTimePicker
locale="en-GB"
today={TODAY}
defaultValue="2026-11-04T13:00"
timeZone="UTC"
/>
</Field>Purpose
Collects a moment such as a meeting, interview or scheduled send as a date plus a wall-clock time. The value is YYYY-MM-DDTHH:mm, the same string as <input type="datetime-local">, so it is never converted between time zones by accident; the zone it belongs to is shown in the timeZone slot. Import from @rookcom/monarch-react/scheduling.
Use when
- Scheduling a meeting, an interview, a reminder or a send time.
- Any form that today uses
type="datetime-local".
Avoid when
- Only a date: use DatePicker.
- Choosing among offered slots (booking): show the slots as buttons instead of free entry.
- A length of time: use DurationInput.
Design principles
- Wall-clock values only: the component never converts zones. The product converts to UTC with the zone it shows.
- The clock follows the locale (12 or 24 hours) and accepts either when typed.
- Picking a date keeps the time; picking a date before any time uses
defaultTime. - On the boundary day of
minormax, a picked date clamps the time into range; a typed out-of-range time is explained, not silently changed.
API reference
import { DateTimePicker } from '@rookcom/monarch-react/scheduling';| Export | Kind | Rendering | Root class |
|---|---|---|---|
DateTimePicker | component | client | .mn-date-time-picker |
The ref goes to the root role="group" element.
The date part is a DatePicker; its messages can be translated through the same messages prop.
Generated from the TypeScript declarations of packages/react/src/components/scheduling/date-time-picker.
Properties
value/onValueChange (controlled) or defaultValue, as YYYY-MM-DDTHH:mm or null.
min/max are date-times; days outside are disabled, times outside on the boundary day are rejected.
timeZone is a slot: a label ("IST", "Europe/London") or a time-zone select.
onValidationChange reports the date part’s errors, invalid-time, or null.
DateTimePicker
A date and a wall-clock time in one field: a DatePicker plus a typed time in the locale's 12- or 24-hour clock, with arrow-key steps and a slot for the time zone. The value is `YYYY-MM-DDTHH:mm`, the same as `<input type="datetime-local">`, so it never shifts with the device's zone.
| Prop | Type | Description |
|---|---|---|
children | ReactNode | |
className | string | |
defaultTime | string | Time used when a date is picked before any time, `HH:mm`. Default `'09:00'`. |
defaultValue | string | null | Initial value (uncontrolled). |
disabled | boolean | |
hourCycle | HourCycle | 12- or 24-hour clock. Default: from the locale. |
id | string | |
invalid | boolean | Marks both parts invalid. Inside a Field, the Field's `invalid` is used. |
isDateDisabled | ((date: IsoDate) => boolean) | Blocks extra dates (weekends, holidays). |
locale | string | BCP 47 locale for typing, display and the calendar. Default: the runtime's. |
max | string | Latest allowed value. |
messages | Partial<DateTimePickerMessages> | Text for translation. |
min | string | Earliest allowed value, `YYYY-MM-DDTHH:mm`. Earlier days are disabled and earlier times on that day rejected. |
name | string | Submits the value (`YYYY-MM-DDTHH:mm`) under this name in a form. |
onValidationChange | ((error: DateTimeValidationError | null) => void) | Called when the built-in validation result changes (`null` when valid). |
onValueChange | ((value: IsoDateTime | null) => void) | Called with a new valid value, or `null` when the date is cleared. |
presets | readonly DatePickerPreset[] | Date quick picks (see DatePicker). The time is kept. |
readOnly | boolean | |
required | boolean | |
size | "sm" | "md" | "lg" | Control height. Default `md`. |
step | number | Minutes the time moves with the Up and Down arrow keys. Default 15. |
timeZone | ReactNode | The time zone the value is in, shown after the time: a label such as "IST" or "Asia/Kolkata", or a time-zone select. The picker itself never converts between zones. |
today | string | Today's date. Default: the device's. |
value | string | null | The wall-clock date and time (controlled), `YYYY-MM-DDTHH:mm`, or `null`. No time zone: see `timeZone`. |
weekStartsOn | Weekday | First day of the calendar week. Default: from the locale. |
Variants
| Prop | Values | Description |
|---|---|---|
hourCycle | '12''24' | Clock format. Default: from the locale. |
step | 'minutes' | How far ↑ and ↓ move the time, snapping to multiples. Default 15. |
size | 'sm''md''lg' | Control height. Default md. |
timeZone | 'none''label''control' | Shown after the time. |
States
| State | Exposed as | Behaviour |
|---|---|---|
| Empty | – | Placeholders show the date format and an example time. |
| Invalid time | aria-invalid="true" on the time input | Unreadable, or outside min/max on that day; a message explains it. |
| Invalid date | aria-invalid="true" on the date input | As DatePicker. |
| Disabled | disabled, data-disabled | Both parts. |
Interaction behaviour
- The date part behaves as DatePicker (typing, calendar, presets, clear). Clearing the date clears the value.
- The time is read on blur and Enter:
14:30,2:30 pm,2pm,1430,9.15all work. - ↑ and ↓ in the time move to the next or previous multiple of
step, wrapping at midnight on the same day. - Typing a time before a date uses today (or the
minday if later).
Keyboard support
| Keys | Action |
|---|---|
| Tab | Date field, its buttons, then the time field. |
| ↑ / ↓ (time) | Later / earlier by step minutes. |
| Enter (time) | Read the typed time. |
| ↓ (date) | Open the calendar (see DatePicker). |
Accessibility
- Role
- group containing two textboxes
- Accessible name
- The group is named by FieldLabel (or
aria-label); the parts are "<label> date" and "<label> time".
- Each part gets
aria-invalidand its own error, linked witharia-describedby. - The time zone is visible text next to the time, not only a tooltip.
- Inside a Field, the label, required state and description apply to both parts.
Responsive behaviour
- Date and time sit in one row and wrap when the container is narrow; on phones the date takes the full width with the time and zone below.
- The calendar popover follows DatePicker’s phone layout.
Theme support
- Input tokens for both parts; every theme and more-contrast mode applies.
- No motion of its own; the calendar respects reduced motion.
Do and don't
Do
- Always show the zone the value is in with
timeZone, and convert to UTC on the server with that zone. - Use
stepthat matches the product’s slots (15 or 30 minutes for meetings).
Don't
- Do not pass
new Date().toISOString()(UTC) as the value; use the wall-clock string in the shown zone. - Do not hide the time part for all-day events; use DatePicker instead.
Related components
- DatePicker: Only a date.
- TimezoneSelect: Let people choose the zone shown in the slot.
- DurationInput: A length of time.
Dependencies
| Kind | Depends on |
|---|---|
| npm packages | react |
| Monarch components | Field, DatePicker |
Testing coverage
- Labelled group with "date" and "time" parts and the zone slot; axe clean.
- 12-hour clock for en-US and through
hourCycle. - Typed times in either clock, on Enter and blur.
- ↑/↓ step and snap to multiples.
- Picking a date first uses
defaultTime; typing a time first uses today. - Unreadable time flagged without changing the value;
onValidationChange. - min/max: days disabled, time clamped on the boundary day, typed times and dates rejected with messages.
- Clearing the date clears the value; controlled value; hidden input; aria-label without Field; disabled.
| Check | Covered |
|---|---|
| Axe in jsdom | Yes |
| Server rendering | Yes |
| Browser suites | Visual baselines: /__gallery/date-time-picker; Cross-browser axe: /components/date-time-picker |
Tests: packages/react/src/components/scheduling/date-time-picker