Rime

DateTimeField and DateTimeRangeField

A date and a time of day on one row, each with its own popup; the range variant pairs a start and end.

DateTimeField composes DateField and TimeField into one control. The parts join as "YYYY-MM-DDTHH:MM" (local, no time zone) — pair with a stored zone when the moment matters across zones; keep it naive when the user types the time in their own time ("show starts 7 pm on Saturday" is the same string whether they're in Sydney or Perth).

min and max are also DateTime strings, so a bound on "2026-10-14T17:00" rules out both a later date and a later time on that same date. The TimeField's own bound widens on dates strictly inside the range and only narrows on the bound dates themselves.

DateTimeRangeField pairs two DateTimeFields with an arrow between them. The start caps the end's min (and vice-versa), so an impossible pick is simply not offered — and if the parent passes an inverted pair, the end sub-group gets a soft danger wash so the row disagrees with itself until it's fixed.

Installation

npx shadcn@latest add KezLahd/rime/date-time-field

Also installs: base, date-field, time-field.

Usage

import { DateTimeField, DateTimeRangeField, type DateTime, type DateTimeRange } from "@/components/ui";

<DateTimeField value={at} onChange={setAt} format="12h" step={15} />

Examples

Date-time and range

API

Generated from the component's TypeScript types and JSDoc (scripts/gen-ui-registry.mjs), so it always matches the source.

DateTimeField

DateTimeField props
PropTypeDefaultDescription
valueRequiredDateTime | null
onChangeRequired(value: DateTime | null) => void
format"12h" | "24h""24h"24h is the default. 12h shows "9:30 AM" and parses am/pm.
stepnumber15Minute granularity for the time popup (default 15).
minDateTime
maxDateTime
disabledboolean
classNamestring
aria-label-datestringaria-label for the date field (default "Date").
aria-label-timestringaria-label for the time field (default "Time").

DateTimeRangeField

DateTimeRangeField props
PropTypeDefaultDescription
valueRequiredDateTimeRange
onChangeRequired(value: DateTimeRange) => void
format"12h" | "24h""24h"
stepnumber15
disabledboolean
classNamestring

Theme tokens

Per-component tokens are undeclared by default, so the default shown is the fallback the CSS uses. Set one at :root (or in theme.css) to restyle every instance. Live values are read from this page, so they follow the Rime Studio.

DateTimeField and DateTimeRangeField per-component tokens
TokenDefaultLive value
--wash-danger-subtlergba(var(--rgb-danger), 0.06)…

System tokens it reads

DateTimeField and DateTimeRangeField system tokens
TokenDefaultLive value
--ink-mutedtokens.css…
--r-mdtokens.css…
--rgb-dangertokens.css…

Accessibility

  • Each piece keeps its own field semantics: the DateField accepts DD/MM/YYYY typing, the TimeField accepts spoken-style times, and both expose their own aria-describedby reason when parsing fails.
  • The TimeField is disabled until a date is set — a time without a day is ambiguous — so keyboard users aren't trapped typing a time that can't be stored.

Do and don't

Do

  • Use this when both pieces matter and the user types them in their own time (events, bookings, deadlines).
  • Pass min and max as full DateTime strings so the TimeField narrows automatically on the boundary dates.

Don't

  • Don't use it for a cross-zone instant; store the time zone alongside the value, or pass a UTC string your layer above knows to translate.

For AI agents

This page as markdown, rendered from the same registry entry. Point an agent at it (or add .md to this page's URL), or at /llms.txt for the index.

Open date-time-field.md

Related: date-field, time-field, date-range-filter