Time Input
Type a time one part at a time, on the clock your user's language uses.
Use a Time Input for a time of day, like a meeting or an opening hour. It works like Date Input, with segments for the hour, the minute and, on a 12-hour clock, AM or PM.
<script setup lang="ts">
import { Field, FieldLabel } from "@ui-sdk/vue/field"
import { TimeInput } from "@ui-sdk/vue/time-input"
</script>
<template>
<Field>
<FieldLabel>Meeting time</FieldLabel>
<TimeInput default-value="09:30" />
</Field>
</template>Installation
npm install @ui-sdk/vue @ui-sdk/coreComposition
Use the following composition to build a TimeInput:
TimeInput
├── TimeInputSegment
└── TimeInputSegmentTimeInput renders a group with one TimeInputSegment for each part of the time, and the text between them.
Usage
Put the input in a Field and give it a label:
<script setup lang="ts">
import { Field, FieldLabel } from "@ui-sdk/vue/field"
import { TimeInput } from "@ui-sdk/vue/time-input"
</script>
<template>
<Field>
<FieldLabel>Meeting time</FieldLabel>
<TimeInput default-value="09:30" />
</Field>
</template>The value is a 24-hour time like "14:30", the same as a native time input's, whatever clock the input shows. Typing, stepping and pasting work as they do in Date Input.
Clock and Seconds
The input shows the locale's clock. Set hour-cycle to 12 or 24 to choose one, and granularity to "second" to add seconds, or "hour" to show the hour alone.
<script setup lang="ts">
import { Field, FieldLabel } from "@ui-sdk/vue/field"
import { TimeInput } from "@ui-sdk/vue/time-input"
</script>
<template>
<div data-slot="stack">
<Field>
<FieldLabel>12-hour clock</FieldLabel>
<TimeInput :hour-cycle="12" default-value="18:45" />
</Field>
<Field>
<FieldLabel>24-hour clock</FieldLabel>
<TimeInput :hour-cycle="24" default-value="18:45" />
</Field>
<Field>
<FieldLabel>With seconds</FieldLabel>
<TimeInput
granularity="second"
:hour-cycle="24"
default-value="18:45:30"
/>
</Field>
</div>
</template>Min and Max
min and max take times like "09:00". A time outside them is invalid: the input sets data-invalid, and its form won't submit.
Form
A hidden input submits the time under name. Set required to need a time before the form submits, and form to the id of a form elsewhere in the page to submit with it. The Date Input form example has a time in it.
Controlled and Controller
Bind v-model:value, or drive the input with createTimeInputController(), as in Date Input.
Styling
Style it like Date Input. The AM/PM segment sets data-type="dayPeriod".
Each part has a data-slot, such as time-input-segment, and its state attributes are listed under Data Attributes.
Data Attributes
TimeInput
[data-slot="time-input"]
| Attribute | What it means |
|---|---|
data-disabled | Present when disabled, by its own prop or a <fieldset>. |
data-readonly | Present when read-only. |
data-required | Present when required. |
data-invalid | Present while the time is before min or after max. |
data-empty | Present while every segment is empty. |
TimeInputSegment
[data-slot="time-input-segment"]
| Attribute | What it means |
|---|---|
data-type | hourminuteseconddayPeriodliteralThe segment's unit, or literal for the text between segments. |
data-disabled | Present when disabled, by its own prop or a <fieldset>. |
data-readonly | Present when read-only. |
data-required | Present when required. |
data-invalid | Present while the time is before min or after max. |
data-empty | Present while the segment is empty. It shows its placeholder. |
API Reference
Props are the same as below, in kebab case in templates, and callbacks are events.
TimeInput
value?string | null- The value: a time like
"14:30", or"14:30:15"with seconds, ornull. Pass it to control the input. defaultValue?string | null- The value it starts with, when uncontrolled, and goes back to when its form resets.
@value-change((value: string | null, details: ChangeDetails<TimeInputValueChangeReason>) => void)- Runs when the value wants to change: once every segment holds something, and again with
nullwhen one is emptied.details.cancel()keeps the value. granularity?TimeInputGranularity- The smallest unit it shows.
hourCycle?HourCycle- A 12 or 24 hour clock. Defaults to the locale's.
min?string- The earliest time, like
"09:00". A time before it is invalid. max?string- The latest time, like
"17:30". A time after it is invalid. locale?string- The language whose separators and clock it shows. Defaults to the page's.
disabled?boolean- Whether it can't be used.
readOnly?boolean- Whether the value can be seen but not changed.
required?boolean- Whether a time must be entered before its form submits.
name?string- The name the value submits under.
form?string- The id of the form it belongs to, when it isn't inside it.
controller?object- Drives it from anywhere. Create one with
createTimeInputController(). debug?boolean- Logs every state change with its reason to the console, in development builds.
State
valuestring | null- The value, or
nullwhile empty or partly filled. segmentsDateInputSegmentData[]- The segments in the order the locale shows them, with the text between them. Render one part for each.
disabledboolean- Whether it can't be used, by itself or by a
<fieldset>. readOnlyboolean- Whether the value can be seen but not changed.
invalidboolean- Whether the value is before
min, aftermaxor an unavailable date.
Reasons
input-changeEvent- Typing, pasting or dropping changed a text field's value; in a combobox it can also open or close it, or Enter keeps the typed text as the value.
step-keyKeyboardEvent- Arrow, Page Up, Page Down, Home or End stepped a slider or a number input.
pasteClipboardEvent- Files were pasted, like a screenshot, or text and tokens into a token input.
resetnone- A form reset.
restorenone- The browser restored state, like after going back, or a saved value was read back from storage.
imperativenone- A controller or
apicall, or a property set on a web component.
Controller
getValue()() => string | null- The value, or
nullwhile empty or partly filled. setValue(value, options?)(value: string | null, options?: DateInputChangeOptions | undefined) => boolean- Sets the value. Returns false when it isn't a value the input can show, or when canceled.
clear(options?)(options?: DateInputChangeOptions | undefined) => boolean- Empties every segment.
focus(segment?)(segment?: string | undefined) => void- Focuses a segment, like
"month", or the first one.
Events
Events get the new value first, then the details. v-model:value only updates when the change wasn't canceled.
| Binding | On | Receives |
|---|---|---|
v-model:value | TimeInput | The time, or null while empty or partly typed |
@value-change | TimeInput | (value, details): the time, or null once it's erased, and the reason |
Accessibility
The root is a group, named by its Field's label or by your aria-label. Each segment is a spinbutton named by its unit, like "hour" or "AM/PM", with its value, range and text. The keys are the same as in Date Input.
Tested Behavior
Every line below is an automated test.
- Each unit is a spinbutton in the locale's order.
- Another locale orders the segments its own way.
- Typing fills each segment, moves on and reports the date once.
- A press on the box or between segments focuses the nearest segment.
- A digit that can't start a longer number moves on at once.
- A separator moves to the next segment.
- Typing with separators over a filled date or time keeps every segment.
- ArrowUp and ArrowDown step a segment and wrap around.
- PageUp and PageDown take bigger steps.
- Home and End go to a segment's first and last values.
- ArrowLeft and ArrowRight move between segments.
- Tab moves through the segments, then out.
- Backspace empties a segment, then moves back.
- A day past the end of a new month is moved back to its last day.
- Pasting a date fills every segment.
- A time takes hours, minutes and AM or PM.
- A 24-hour clock has no AM or PM.
- A date with a time shows its hour and minute too.
- A controller sets and clears the date.
- A canceled change keeps the date.
- The form submits the ISO date and time under their names.
- Enter submits the form with what was typed.
- Resetting the form brings back the default date.
- A partly filled date can't be submitted.
- A required empty date can't be submitted.
- A date after max is invalid.
- An unavailable date is invalid.
- The field's label focuses the first segment.
- A read-only date takes focus but doesn't change.
- A disabled date can't be focused.
Runs in React, Vue and web components.