vaiperui

components / date-time-picker

DateTimePicker

Field that opens a Calendar and time columns to choose a day and a time.

How to use

Combines `Calendar` and the `TimePicker` columns in one panel. The value is a `Date` with the day and the time (seconds are ignored). Picking a day keeps the time; picking a time before a day uses today. The panel stays open until `OK`, `Esc` or a click outside. With `name`, the form receives `yyyy-mm-ddTHH:mm`.

preview
DateTimePicker.tsx
import { DateTimePicker } from "vaiperui";
const [when, setWhen] = useState<Date>();
<DateTimePicker label="Appointment" value={when} onValueChange={setWhen} />
<DateTimePicker label="Appointment" hour12 minuteStep={15} minDate={new Date()} />

24h and 12h

preview
24h
12h
hour-cycle.tsx
<DateTimePicker />
<DateTimePicker hour12 />

Limits

preview
min / maxDate, step 15
limits.tsx
<DateTimePicker minDate={new Date()} minuteStep={15} />

Sizes

preview
sm
md
lg
sizes.tsx
<DateTimePicker size="sm" />
<DateTimePicker size="md" />
<DateTimePicker size="lg" />

States

preview
Extra detail
helper
This is required
error
disabled
read only
states.tsx
<DateTimePicker label="..." helperText="..." />
<DateTimePicker label="..." errorMessage="..." />
<DateTimePicker label="..." disabled />
<DateTimePicker label="..." readOnly />

Props

PropValuesDefaultDescription
value / defaultValueDatenoneDay and time, controlled or initial
onValueChange(date: Date) => voidnoneCalled when the day, hour, minute or period changes
confirmLabelstring"OK"Text of the button that closes the panel
hour12booleanfalse12h with an AM/PM column
minuteStepnumber1Granularity of the minutes column
labels{ hours, minutes, period, am, pm }noneTexts of the time columns
label / helperTextstringnoneLabel above the field and help text below
errorMessagestringnoneError text; its presence alone forces the error state
placeholderstringfrom the localeText when nothing is chosen (e.g. mm/dd/yyyy)
namestringnoneForm field name
disabled / readOnlybooleanfalseDoes not open the panel; readOnly still shows the value
variantring | outlineringFocus style, same as Input
size / radiussm | md | lg / none | sm | md | lg | fullmd / mdField height and corner rounding
aria-labelstringnoneAccessible name when there is no label
panelLabelstringnoneAccessible name of the open panel
minDate / maxDateDatenoneFirst and last allowed day; the rest and the month arrows leading outside are disabled
localestring"en-US"Language of month/day names and the date format (BCP 47)
weekStartsOn0 – 60First weekday (0 = Sunday)
previousMonthLabel / nextMonthLabelstring"Previous month" / "Next month"Accessible names of the month buttons
variantColor / customColor / animationprimary | success | warning | danger / CSS color / none | smooth | fast | bounceprimary / smoothColor of the selection and focus, and transition speed

Accessibility

  • The trigger is a `<button>` with `aria-haspopup="dialog"` and `aria-expanded` reflecting the panel state.
  • `label` is linked with `htmlFor`; without `label`, the trigger uses `aria-label`.
  • `errorMessage` sets `aria-invalid` and `aria-describedby` to the message; otherwise `helperText` is linked through `aria-describedby`.
  • The panel is a `role="dialog"` named by `panelLabel`, rendered in a portal on `document.body`.
  • `disabled` disables the button; `readOnly` keeps it focusable but the panel never opens.
  • The panel holds a `Calendar` (focused on open, grid pattern) and the time columns, each a `role="group"` named by `labels`.
  • Time options are `<button>`s with `aria-pressed` on the selected one; a final confirm button (`confirmLabel`) closes the panel.

Keyboard

KeyAction
Enter / SpaceOpens or closes the panel from the trigger.
Arrow keys, Home, End, Page Up/DownIn the calendar, navigate the days (see Calendar); picking a day keeps the chosen time and does not close the panel.
Arrow Up / DownIn a time column, moves focus to the previous / next option.
TabMoves from the calendar to the time options and the confirm button.
EscCloses the panel and returns focus to the trigger.

Keep in mind

  • The panel does not trap focus: Tab leaves it, and because it is rendered at the end of `<body>`, Tab from the trigger does not enter it on its own.
  • Clicking outside closes the panel without moving focus back; only Esc restores focus to the trigger.
  • Date and time cannot be typed. Pass `labels`, `confirmLabel`, `panelLabel` and the month button labels translated; the defaults are in English.