Vize

Time Field

Accessible, unstyled segmented time input with 12/24-hour clocks and hour/minute/second granularity.

Package @vizejs/ui/time-field
Maturity stable
Own the source vize lib pull time-field
Requires controllable-state, date-field, id, locale
Aliases time input, segmented time, clock input, hh:mm
Covers WAI-ARIA spinbutton, React Aria TimeField, Reka UI TimeField, HTML input type=time

Usage

import { TimeField } from "@vizejs/ui/time-field";

Or copy the source into your project with vize lib pull time-field (see Source Distribution).

API

TimeField

Source: src/families/date-time/time-field/time-field.vue

Props

Prop Type Default Description
id string | null | undefined undefined Consumer-owned group id; nullish values use a deterministic fallback.
name string | undefined undefined Hidden input name that submits HH:MM or HH:MM:SS with forms.
modelValue PlainTime | null | undefined undefined Controlled time; undefined selects uncontrolled mode and null clears.
defaultValue PlainTime | null | undefined null Initial uncontrolled time and native form-reset target.
min PlainTime | null | undefined undefined Earliest valid time; earlier values mark the field invalid.
max PlainTime | null | undefined undefined Latest valid time; later values mark the field invalid.
hourCycle HourCycle | undefined undefined 12 shows 1–12 plus an AM/PM segment, 24 shows 0–23; defaults to the locale clock.
granularity TimeGranularity | undefined "minute" Smallest edited unit; second adds a seconds segment.
placeholderValue PlainTime | null | undefined { hour: 0, minute: 0, second: 0 } Time whose segments seed arrow-key stepping from empty.
locale string | undefined undefined BCP 47 locale deciding segment order, clock, and labels; defaults to the nearest LocaleProvider.
dir "ltr" | "rtl" | undefined undefined Text direction for arrow-key segment movement; defaults to the nearest LocaleProvider.
disabled boolean | undefined false Remove every segment from focus and editing.
readOnly boolean | undefined false Keep segments focusable while blocking edits.
required boolean | undefined false Require a complete value; participates in native form validation.
invalidMessage string | undefined "Invalid value" Custom validity message reported while the value is out of range or unavailable.
placeholders FieldSegmentPlaceholders | undefined { hour: "––", minute: "––", second: "––", dayPeriod: "––" } Placeholder text for empty segments.
emptyText string | undefined "Empty" Text announced for empty segments.
ariaLabel string | undefined undefined Accessible name for the segment group.
ariaLabelledby string | undefined undefined Ids that label the segment group.
ariaDescribedby string | undefined undefined Ids that describe the group and every segment.
ariaErrormessage string | undefined undefined Id of the validation message used while invalid.
ariaInvalid boolean | undefined false Force the invalid state in addition to built-in min/max validation.

Events

Event Payload Description
update:modelValue [value: PlainTime | null] Fired when segments request a new controlled time or null while incomplete.
change [value: PlainTime | null, previous: PlainTime | null, nativeEvent: Event | null] Fired after a distinct committed time with the previous time and triggering event.

Slots

Slot Slot props Description
default TimeFieldSlotState Extra content after the segments, such as a picker trigger. Receives field state.
segment FieldSegmentState Segment content. Receives the segment state; defaults to its text.

Behavior

Normative state x input -> outcome table for time-field.vue (@vizejs/ui/time-field). TimeField shares the DateField segment engine, so DateField rows F2–F8, F10–F12, and F15 (native required validation) apply to hour, minute, second, and day-period segments. Every row below is proven by the named test.

# State Input Outcome Proven by
T1 locale clock render segment order, hour padding, and day-period labels follow Intl; hourCycle forces 12 or 24; granularity adds or removes minute/second segments renders locale clocks: 12-hour with a day period or 24-hour without
T2 12-hour, empty digits and a/p hours, minutes, and the day period fill in order and commit a 24-hour PlainTime; letters and arrows toggle AM/PM typing hours, minutes, and a day period commits a 24-hour value
T3 12-hour step 12 AM is midnight and 12 PM is noon; hours wrap 12→1 without flipping the period; minutes wrap and Page steps by 15 12 AM and 12 PM map to midnight and noon; hours wrap within the clock
T4 24-hour, seconds digits two-digit hours wait for the second digit when it can fit; second granularity commits only after seconds; no hidden input without name 24-hour typing accepts two-digit hours and seconds granularity requires seconds
T5 min / max commit / empty step out-of-window times are invalid; placeholderValue seeds stepping from empty min and max mark times invalid; placeholderValue seeds empty stepping
T6 disabled/read-only keys no edits are committed disabled and read-only time fields block edits
T7 imperative expose / clock change hourCycle, granularity, focus, setValue, clear; switching the clock re-renders the same time exposes hour cycle, granularity, and imperative editing
T8 time model helpers PlainTime validation, comparison, truncation, and HH:MM[:SS] round-trips plain time helpers validate, compare, truncate, and round-trip ISO text
T9 SSR/hydration isolated requests byte-identical segments and deterministic ids hydrate silently renders byte-identical locale-ordered time segments across SSR requests, hydrates time segments with generated ids and no mismatches

Root data adds data-hour-cycle (12/24) and data-granularity to the DateField hooks, with data-vize-ui="time-field", time-field-segment, and time-field-literal. The hidden input submits HH:MM, or HH:MM:SS for second granularity.