Skip to content

Early previewhamur is not on npm yet. The components are being built in the open, follow along on GitHub.

InputsReact

Date Time Field

A date and a time typed in one row of segments: the date segments of DateField and the time segments of TimeField, in the locale's order.

Rendered by React 19.3.1

Loading React…
import * as React from 'react'
import { DateTimeField } from '@hamur/react/date-time-field'
import { Field } from '@hamur/react/field'

export default function DateTimeFieldExample() {
  const [value, setValue] = React.useState<string | null>(null)
  return (
    <Field.Root className="field">
      <Field.Label>Meeting</Field.Label>
      <DateTimeField.Root
        className="date-field"
        locale="en-US"
        today="2026-11-07"
        onValueChange={(next: string | null) => setValue(next)}
      >
        <DateTimeField.Input className="date-field-input">
          {({ segments }) =>
            segments.map((segment) => (
              <DateTimeField.Segment
                key={segment.index}
                segment={segment}
                className="date-field-segment"
              />
            ))
          }
        </DateTimeField.Input>
        <DateTimeField.Clear className="date-field-clear">
          ×
        </DateTimeField.Clear>
      </DateTimeField.Root>
      <p className="muted">Value: {value ?? 'none'}</p>
    </Field.Root>
  )
}
Not measured yetTests passing in React
Not measured yetSize
Not measured yetMemory
Not measured yetSpeed
[N] commits

Installation

npm i @hamur/react

Not on npm yet. The package goes out under the chosen name.

Anatomy

Import the component and assemble its parts:

<DateTimeField.Root>
  <DateTimeField.Input>
    <DateTimeField.Segment />
  </DateTimeField.Input>
  <DateTimeField.Clear />
</DateTimeField.Root>

Examples

The demo at the top is the one example this component has so far.

API reference

27 props across 4 parts, in React syntax. className, style, render are listed once, under Shared props.

ClearDateTimeField.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>.

InputDateTimeField.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>.

Input props
PropTypeDefault
childrenThe segments, or a function of them: ({ segments }) => ....React.ReactNode | ((context: { segments: FieldSegment[]; }) => React.ReactNode)—

RootDateTimeField.Root

Groups all parts of a field that edits a date and a time in segments. Values are strings such as '2026-11-07T14:30'; HTML's space instead of T is accepted. Renders a <div>.

Root props
PropTypeDefault
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.booleantrue
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.booleanfalse
readOnlyWhether the user should be unable to change the value.booleanfalse
requiredWhether the user must fill in the field before submitting a form.booleanfalse
invalidWhether the field is invalid.booleanfalse
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.`${number}-${number}-${number}T${number}:${number}${string}` | null—
defaultValueThe value when initially rendered.`${number}-${number}-${number}T${number}:${number}${string}` | null—
onValueChangeEvent handler called when the value changes: a complete value, or null when a complete((value: `${number}-${number}-${number}T${number}:${number}${string}` | null, eventDetails: DateFieldRootChangeEventDetails) => void)—
minThe earliest valid value.`${number}-${number}-${number}T${number}:${number}${string}`—
maxThe latest valid value.`${number}-${number}-${number}T${number}:${number}${string}`—
hourCycleThe hour cycle, 12 (with a day period segment) or 24.12 | 24—
granularityThe finest segment shown.TimeGranularity—
stepThe native step in seconds.number—
isDateUnavailableWhether a date cannot be chosen.((date: `${number}-${number}-${number}`) => boolean)—
Root data attributes
Data attributeDescription
data-disabledPresent when the field is disabled.
data-readonlyPresent when the field does not allow changing the value.
data-requiredPresent when the field is required.
data-emptyPresent when no segment has a value.
data-filledPresent when every segment has a value.
data-incompletePresent when some segments have a value and others do not.
data-focusedPresent when focus is inside the field.
data-invalidPresent when the field is invalid.

SegmentDateTimeField.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>.

Segment props
PropTypeDefault
segmentrequiredThe segment to render, one of the segments the Input gives its children.FieldSegment—

Shared props

Every part that renders an element takes these.

Shared props
PropType
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

Keyboard
KeysDoesPart
Type into the segment and move on when it is full, from the year into the hourSegment
ArrowUpArrowDownStep the segment by one and wrap, without carrying into the nextSegment
PageUpPageDownStep by the segment's page amount: day 7, month 3, year 10, hour 6, minute and second 15Segment
ArrowLeftArrowRightMove to the previous or next segment, swapped in right to leftSegment
BackspaceDeletes the last digit; on an empty segment, moves to the previous oneSegment
EnterEscapeNot capturedSegment
ControlMetaAltUntouchedSegment

Accessibility

What the parts set
PartSetsSo that
Rootrole="group", aria-labelledby the Field label and a visually hidden text of the full date and timetabbing in reads "Meeting, Thursday, November 12, 2026 at 2:30 PM" once
Segmentrole="spinbutton" with its name, range and value, as in DateField and TimeFieldeach part is read on its own, and an empty one says "Empty"
Segmentaria-invalid and aria-errormessage when the value is invalidthe error is on the element that has focus
Cleararia-label "Clear" (from labels), tabindex="-1"the button is named and adds no tab stop

Focus order

  1. Each editable segment is a tab stop, the date first and then the time in en-US.
  2. A full segment moves focus on unless autoAdvance is false; the year moves on to the hour.
  3. Clear is out of the tab order.