DateTimePicker
v1.0.16Updated 19 Oct 2026Combined date + time-of-day picker: a Popover calendar with an Hour/Minute Select row beneath it, merging both into one Date value. Minute options are step-filtered via `minuteStep` (default 5), and an off-grid current minute (e.g. :37 on a 5-minute step) is spliced in so the control never misrepresents the stored time. Supports Buddhist Era (พ.ศ.) and Thai locale labels.
Preview
Live · 9 stories▸Why this is recommendeddatetimedatetimedatetimepicker+6
DateTimePicker — date time.
- ✓Scheduling a meeting start time
- ✓Setting an appointment date and time
- ✓Choosing a send/publish timestamp
- ✓Booking a slot with a specific time
- ✓Setting a reminder date and time
- ✓Recording an event date and time in a form
- Date and time-of-day in a single Popover
- Hour + minute Select dropdowns
- minuteStep filtering (default 5) with off-grid minute preserved
- Seconds and milliseconds zeroed on time change
- Controlled (date) or uncontrolled (defaultDate)
- Thai Buddhist Era calendar + Thai locale labels
- BE/CE era toggle chip — the choice STICKS across reopens, and is readable/settable via calendarMode (fb_20a80f6c)
- i18n: calendar month/weekday names and year digits follow the app LocaleProvider (useB69Locale) for non-Thai locales
- Labelled by FormField: id, aria-describedby and aria-invalid land on the trigger button (its label names it) and the trigger fills the field column (standalone w-64); the popover hour / minute selects keep their own names
- ✕Date-only selection (use DatePicker — it avoids loading Select)
- ✕Selecting a date range (use DateRangePicker)
- ✕Time-only entry with no date (use TimePicker)
- ✕Fast keyboard-only entry of precise times (use a text time field)
Install
Ask your agent, or call the MCP tool directly. The resolved bundle is written into your project.
Usage
Tick variants in the left menu — each adds a tab with that variant’s real story source, the same code the preview above renders.
Props
dateSelected date + time (controlled)
—onDateChangeSelection callback
—defaultDateInitial value for uncontrolled usage (ignored when `date` is provided)
—minuteStepMinute granularity in the dropdown (default 5)
—placeholderTrigger text when nothing is selected (default "Pick a date & time", or "เลือกวันที่และเวลา" under locale="th"). It used to be hardcoded English, so a Thai field announced itself in two languages; it is now a `labels` key too, and this prop still wins over it
—formatStrdate-fns format string (default "MMM d, yyyy 'at' HH:mm")
—alignPopover alignment
—calendarThe era the field shows by DEFAULT (default "gregory"); "buddhist" renders พ.ศ. years and puts the era chip in the footer. "gregorian" is the deprecated spelling — still accepted and normalised on arrival, so a host passing its own stored Intl calendar value through no longer gets TS2322 and has to translate the word by hand (fb_e8de80fb). The `data-calendar` attribute still writes "gregorian", because consumers already style and test against it
—calendarModeWhich era the picker is SHOWING, as a controlled value. Pair with `onCalendarModeChange` to remember the user's choice across opens or sessions. Left alone the picker keeps its own, seeded from `calendar` — and no longer resets it when the popup reopens, which is what stopped the era chip from sticking (fb_20a80f6c). Presentation only: the Date handed back is the same Date in either era. The deprecated "gregorian" spelling is accepted here too and normalised on arrival, so an era a host stored under the old word can be fed straight back in without a type error (fb_e8de80fb); `onCalendarModeChange` always reports the house spelling
—onCalendarModeChangeFires with the era the user switched the picker to
—showEraChipShow the era chip even when `calendar` is gregorian, so a ค.ศ. field can be switched to พ.ศ. (default false — a chip appearing in footers that never had one is a change other consumers did not ask for)
—localeLocale for labels and formatting. `locale="th"` now also supplies the Thai BUILT-IN strings (placeholder, era chip พ.ศ./ค.ศ., and for DateRangePicker the whole quick-range rail) — previously the grid localised but the trigger stayed English, which only showed on an EMPTY field. An explicit `labels` (or `placeholder`) still wins, and locale="en" is unchanged. MCP feedback fb_3adc3df4.
—labelsOverride the built-in UI strings (i18n): placeholder, time, hours, minutes, be, ce, toggleCalendarEra. The three era keys are forwarded to the era chip; `placeholder` is here because the trigger used to hardcode "Pick a date & time" and showed it under a Thai grid. Merged over the locale defaults (DEFAULT_DATE_TIME_PICKER_LABELS, or TH_DATE_TIME_PICKER_LABELS under locale="th"), so a partial object only replaces the keys it names; the explicit `placeholder` prop still wins over labels.placeholder
—disabledDisables the trigger
—invalidMark the field invalid (destructive ring); aria-invalid wins when both are set
—idDOM id set on the trigger button; FormField clones its field id in, and its label then names the control
—aria-labelAccessible name of the trigger when there is no visible label
—aria-labelledbyId(s) of the element(s) that label the trigger; wins over a FormField label
—aria-describedbyId(s) of hint or error text describing the trigger (FormField clones this in)
—aria-invalidMark the trigger invalid; FormField clones this in from its error prop
—aria-requiredAccepted (FormField clones it in) but not rendered: ARIA does not allow it on a button. The label text "required" is part of the name instead
—