TimeInput

TimeInput accepts a 24-hour time without opening a picker. Choose it when typing a precise value is the efficient path; use TimePicker when people need to browse a set of available times.

Examples

A normalised 24-hour time

People can type 9, 0930 or 9:5. Blur or Enter parses a valid entry, normalises it to HH:mm and calls onChange with that value.

Enter a 24-hour time, such as 09:30.

Bounds and increments

min and max clamp committed and stepped values. Arrow keys and the steppers move by step; hold Shift with an arrow key to move by one hour.

Translated spoken controls

Use labels to replace the English stepper names and to provide the spoken aria-valuetext for a selected time. Unspecified labels keep their English defaults.

When to use

Use TimeInput when a person knows or can efficiently type a single 24-hour time.

Reach for something else when:

  • The available times need to be browsed from a list — use TimePicker, which is designed for that selection flow.
  • Only a date is needed — use a date-specific control rather than accepting an ambiguous time.
  • A duration is being entered — use separate duration fields or a control that names units instead of treating it as a clock time.

Accessibility

  • Renders a text input with role="spinbutton", numeric input mode and aria-valuemin, aria-valuemax and aria-valuenow in minutes. A supplied label is connected through htmlFor.
  • The two mouse stepper buttons are removed from the tab order; keyboard users adjust the focused input with ArrowUp and ArrowDown. Shift plus an arrow moves one hour.
  • A selected value receives aria-valuetext from labels.valueText; use labels to translate the default English stepper names and spoken value.
  • Invalid text is deliberately preserved on blur or Enter, marked invalid, and does not call onChange. A valid value is normalised and committed; an intentional empty value commits null.
  • error replaces hint, is connected through aria-describedby, and sets aria-invalid. invalid can set invalid styling without a visible error message.

API and code

NameTypeRequiredDescription
labelstring—Label rendered above the input and connected with htmlFor.
hintstring—Helper text rendered below the input. Replaced by error when present.
errorstring—Error message that enables error styling and replaces hint.
valuestring | null—Controlled 24-hour HH:mm value, or null for no selected time.
defaultValuestring—Initial 24-hour HH:mm value in uncontrolled mode.
onChange(time: string | null) => void—Called with a normalized HH:mm value, or null after the field is cleared.
stepnumber—Minutes added or subtracted by the steppers and Arrow keys. Default: 15.
minstring—Inclusive HH:mm lower limit. Values below it are clamped.
maxstring—Inclusive HH:mm upper limit. Values above it are clamped.
size'sm' | 'md' | 'lg'—Control height. Default: "md".
invalidboolean—Enables invalid styling and aria-invalid without an error message.
labelsTimeInputLabels—Translatable accessible labels, merged over the English defaults.
disabledboolean—Disables the input and steppers.

x-data="lyraTimeInput({ … })"

OptionTypeRequiredDescription
defaultValuestring—Initial 24-hour HH:mm value, or no selection when omitted.
stepnumber—Minutes added or subtracted by steppers and Arrow keys. Default: `15`.
minstring—Inclusive 24-hour HH:mm lower limit.
maxstring—Inclusive 24-hour HH:mm upper limit.
invalidboolean—Enables consumer-driven invalid styling and `aria-invalid`.
valueText(hours: number, minutes: number) => string—Spoken value for a selected time.

Without React, use the same structure and implement parsing, clamping and keyboard behaviour yourself:

html
<div class="lyra-field">
  <label class="lyra-label" for="start-time">Start time</label>
  <span class="lyra-timeinput">
    <input
      class="lyra-input"
      id="start-time"
      type="text"
      role="spinbutton"
      inputmode="numeric"
      aria-valuemin="0"
      aria-valuemax="1439"
      aria-valuenow="570"
      aria-valuetext="9 hours and 30 minutes"
      value="09:30"
    />
    <span class="lyra-timeinput__steppers">
      <button class="lyra-timeinput__step" type="button" tabindex="-1" aria-label="Later">▲</button>
      <button class="lyra-timeinput__step" type="button" tabindex="-1" aria-label="Earlier">
        ▼
      </button>
    </span>
  </span>
  <span class="lyra-hint">Enter a 24-hour time.</span>
</div>

<lyra:time-input> Generated from lyra-ds/blade v0.10.0.

The behavior comes from lyraTimeInput() — install @lyra-ds/alpine and see the HTML + Alpine tab.

PropDefaultRequiredExample values
labelnull—Start time
hintnull—Use 24-hour time
errornull—Invalid Invalid time
valuenull——
defaultValuenull——
step15——
minnull——
maxnull——
size'md'—lg sm
invalidfalse——
labels[]——
disabledfalse——
blade
<lyra:time-input
    name="start_time"
    label="Start time"
    default-value="09:00"
    :step="15"
    min="08:00"
    max="18:00"
    size="md"
/>