DateTimeField

A React datetime picker - a month calendar plus a segmented time input in one popover. For scheduling forms.

DateTimeField playground

Type into the segments or spin them with the arrow keys - the calendar and the clock commit live.

Install DateTimeField

1. New project? One command installs the package and wires everything - see Installation:

bash
pnpm dlx zyncat-ui init

2. Import the component - it loads its own stylesheet:

tsx
import { DateTimeField } from '@zyncat/ui/datetime-field';

Usage

tsx
import { DateTimeField } from '@zyncat/ui/datetime-field';
 
<DateTimeField label="Publish timestamp" value={datetime} onChange={setDatetime} />

Compose DateTimeField in your application. No Tailwind or external styling library is required; every value resolves from Zyncat UI's token vocabulary.

DateTimeField props

DateTimeField

PropTypeDefaultDescription
valuestring | null—Controlled value, 'YYYY-MM-DDTHH:mm'.
defaultValuestring | nullnullUncontrolled initial value, 'YYYY-MM-DDTHH:mm'. Use instead of `value`.
onChange(value: string) => void—Fires once both date and time are set, with 'YYYY-MM-DDTHH:mm' (an incomplete half never commits).
placeholderstring'Pick date & time'Trigger text shown when no value is picked.
timezonestring—IANA timezone (e.g. 'Europe/Riga') - display context, shown in the footer.
minstring—Lower bound - 'YYYY-MM-DD' or 'YYYY-MM-DDTHH:mm', inclusive.
maxstring—Upper bound - 'YYYY-MM-DD' or 'YYYY-MM-DDTHH:mm', inclusive.
format'24h' | '12h'—Time display only; storage stays 24h. Default '24h'.
minuteStepnumber—↑/↓ step granularity in minutes (typing is exact). Default 5.
labelstring—Field label rendered above the trigger.
requiredbooleanfalseAsterisk on the label.
invalidbooleanfalseDanger border + message color (.zc-fld.zc-is-error).
messagestring—Helper / error text under the field.
disabledbooleanfalseDisable the field.
size'sm' | 'md' | 'lg''md'Control height, type and padding - the same scale as `TextField`, so a form row can hold one size throughout.
classNamestring—Extra class on the field shell root.
...htmlAttributesHTMLAttributes<HTMLDivElement> & DataAttributes—Standard <div> attributes (style, data-*, aria-*, ...) forwarded to the field shell root.
activateOnActivateOn'pointerdown'Whether the trigger, the day cells and the panel controls fire on `pointerdown` (snappier) or wait for `click`. (Not used by TimeField, which is inline.)
animationDisableableAnimation—Popover open/close timing - motion tokens only, or `null` to disable. (Not used by TimeField, which is inline.)

Frequently asked questions

Import it per subpath and give it a label and a value: import { DateTimeField } from '@zyncat/ui/datetime-field', then <DateTimeField label="Publish timestamp" value={datetime} onChange={setDatetime} />. It is a client component, so it drops straight into the Next.js App Router. onChange only fires once both the day and the time are set - pick a date and leave the time blank and nothing commits yet, which is why picking either half first never produces a half-finished value.

Because that string is exactly the value format the native <input type="datetime-local"> uses - value, defaultValue, min and max all take the same 'YYYY-MM-DDTHH:mm' shape. It sorts correctly as a string, drops straight into a datetime-local form field or a timestamp column, and new Date(value) parses it directly on the rare occasion you need the object.

Yes - min and max each accept either 'YYYY-MM-DD' for a whole-day bound or the full 'YYYY-MM-DDTHH:mm' to also bound the time. Pass max="2026-09-02T17:00" and every day up to September 2 stays fully open, but the moment you pick September 2 itself, the time segments clamp to 17:00 and below.

No - timezone only labels the footer with that zone's current GMT offset, read via Intl.DateTimeFormat; it never shifts the committed 'YYYY-MM-DDTHH:mm' string. Pass an IANA name like timezone="Europe/Riga" for context next to the Done button, and treat the value itself as the local time the user actually clicked.

No - @zyncat/ui has zero runtime dependencies and React 19 as its only peer, while MUI X's date pickers need a date-library adapter (date-fns, dayjs, luxon or moment) just to render. The calendar grid, the min/max clamping and the hour/minute stepping all run on the built-in Date and plain string comparison, with Intl.DateTimeFormat used only for the optional timezone label.

Both - the Hours and Minutes segments are role="spinbutton" controls you can type digits into directly (type 1 then 4 for 14, and focus jumps to Minutes automatically), or step with ArrowUp/ArrowDown, minutes moving by the minuteStep prop (default 5). Backspace clears a segment, arrow keys move between segments, and pasting text like "3:45 PM" fills both at once; under prefers-reduced-motion the month-slide and the selected-day pill settle instantly instead of animating.

Set in Geist & Newsreader — animated by the house engineZyncat UI · Rev 0.11 · MIT · Built by Tabsir Ahammed · Source on GitHub