InputsReact
A time of day typed in segments: hour, minute, optional seconds and, in a 12-hour cycle, a day period (AM or PM).
Rendered by React 19.3.1
Loading React…Installation
npm i @hamur/reactNot on npm yet. The package goes out under the chosen name.
Anatomy
Import the component and assemble its parts:
<TimeField.Root>
<TimeField.Input>
<TimeField.Segment />
</TimeField.Input>
<TimeField.Clear />
</TimeField.Root>Examples
24h Seconds
hourCycle={24} and granularity="second": hour, minute and second, and the value beneath reads 14:30:15.
API reference
26 props across 4 parts, in React syntax. className, style, render are listed once, under Shared props.
ClearTimeField.Clear
Clears the whole value, including a partly typed one. It is out of the tab order: Backspace clears a segment from the keyboard. Renders a <button>.
InputTimeField.Input
The visual control: it wraps the segments. Its children are a function of the segments, since their order depends on the locale; without children it renders every segment. Renders a <div>.
| Prop | Type | Default |
|---|---|---|
childrenThe segments, or a function of them: ({ segments }) => .... | React.ReactNode | ((context: { segments: FieldSegment[]; }) => React.ReactNode) | — |
RootTimeField.Root
Groups all parts of a field that edits a time of day in segments (hour, minute, optional seconds, day period). Values are strings such as '14:30', '14:30:15' or '14:30:15.250'; every HTML form is accepted and one canonical form is reported. Renders a <div>.
| Prop | Type | Default |
|---|---|---|
onIncompleteChangeEvent handler called when the segments change while no complete value exists, with the | ((parts: FieldParts, eventDetails: DateFieldRootChangeEventDetails) => void) | — |
localeThe BCP 47 locale of the segment order, literals, digits and day periods. | string | 'en-US' |
forceLeadingZerosWhether the day, month and hour show a leading zero. | boolean | — |
placeholderValueThe value an empty segment takes on its first Up or Down press. | string | — |
todayThe date of today ('2026-11-07'), for the starting point of an empty date segment. | `${number}-${number}-${number}` | — |
timeZoneThe time zone that decides what today is, when today is not given. | string | — |
autoAdvanceWhether focus moves to the next segment when the typed number cannot get another digit. | boolean | true |
segmentRoleThe role of the segments. | DateFieldSegmentRole | 'spinbutton' |
labelsThe texts the field adds: the segment names, the text of an empty segment, the Clear label. | Partial<DateFieldLabels> | — |
disabledWhether the component should ignore user interaction. | boolean | false |
readOnlyWhether the user should be unable to change the value. | boolean | false |
requiredWhether the user must fill in the field before submitting a form. | boolean | false |
invalidWhether the field is invalid. | boolean | false |
nameIdentifies the field when a form is submitted. | string | — |
formIdentifies the form that owns the hidden input. | string | — |
inputRefA ref to access the first segment. | React.Ref<HTMLInputElement> | — |
valueThe value, null for none. | TimeString | null | — |
defaultValueThe value when initially rendered. | TimeString | null | — |
onValueChangeEvent handler called when the value changes: a complete value, or null when a complete | ((value: TimeString | null, eventDetails: DateFieldRootChangeEventDetails) => void) | — |
minThe earliest valid value. | TimeString | — |
maxThe latest valid value. | TimeString | — |
hourCycleThe hour cycle, 12 (with a day period segment) or 24. | 12 | 24 | — |
granularityThe finest segment shown. | TimeGranularity | — |
stepThe native step in seconds. | number | — |
| Data attribute | Description |
|---|---|
data-disabled | Present when the field is disabled. |
data-readonly | Present when the field does not allow changing the value. |
data-required | Present when the field is required. |
data-empty | Present when no segment has a value. |
data-filled | Present when every segment has a value. |
data-incomplete | Present when some segments have a value and others do not. |
data-focused | Present when focus is inside the field. |
data-invalid | Present when the field is invalid. |
SegmentTimeField.Segment
One segment of the value. An editable segment (year, month, day, hour, minute, second, millisecond, day period) is a real <input> with the spinbutton role; a literal (/, :) is a <span> hidden from assistive technology., or a <span> for a literal. Renders an <input>.
| Prop | Type | Default |
|---|---|---|
segmentrequiredThe segment to render, one of the segments the Input gives its children. | FieldSegment | — |
Shared props
Every part that renders an element takes these.
| Prop | Type |
|---|---|
classNameCSS class applied to the element, or a function that
returns a class based on the component's state. | string | ((state: State) => string | undefined) |
styleStyle applied to the element, or a function that
returns a style object based on the component's state. | React.CSSProperties | ((state: State) => React.CSSProperties | undefined) |
renderAllows you to replace the component's HTML element
with a different tag, or compose it with another component. | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, State> |
Keyboard and accessibility
Keyboard
| Keys | Does | Part |
|---|---|---|
| Types into the segment and moves on when it is full: in a 12-hour cycle the hour 1 waits for 10 to 12 | Segment | |
| AP | On the day period, set AM or PM; other letters are ignored | Segment |
| ArrowUpArrowDown | Step the segment by one, or the minute and second by step when it divides evenly; on the day period, toggle | Segment |
| PageUpPageDown | Step the hour by 6 and the minute and second by 15 | Segment |
| HomeEnd | Set the segment to its smallest or largest number | Segment |
| ArrowLeftArrowRight | Move to the previous or next segment, swapped in right to left | Segment |
| Backspace | Deletes the last digit; on an empty segment, moves to the previous one | Segment |
| Delete | Clears the segment | Segment |
| EnterEscape | Not captured: Enter submits the form, Escape is left to a dialog around the field | Segment |
| ControlMetaAlt | Untouched: copy, undo and the browser's shortcuts work | Segment |
Accessibility
| Part | Sets | So that |
|---|---|---|
| Root | role="group", aria-labelledby the Field label and a visually hidden text of the full time | tabbing in reads "Start time, 2:30 PM" once |
| Segment | role="spinbutton", aria-label the segment's name, aria-valuenow when filled, aria-valuetext for a 12-hour hour with its period, and "Empty" | the hour is read "2 PM", not "2", and an empty segment says so |
| Segment | inputmode="numeric" on the numbers and inputmode="text" on the day period | a phone shows digits for the numbers and letters for AM and PM |
| Segment | aria-invalid and aria-errormessage when the time is invalid | the error is on the element that has focus |
| Clear | aria-label "Clear" (from labels), tabindex="-1" | the button is named and adds no tab stop |
Focus order
- Each editable segment is a tab stop: hour, minute, second, then the day period in
en-US. - A full segment moves focus on unless
autoAdvanceisfalse. - Clear is out of the tab order.