Time Field
A time field allows users to enter and edit time values using a keyboard. Each part of a time value is displayed in an individually editable segment.
Import
tsimport { TimeField } from "@kobalte/core/time-field";// orimport { Root, Label, ... } from "@kobalte/core/time-field";
tsimport { TimeField } from "@kobalte/core/time-field";// orimport { Root, Label, ... } from "@kobalte/core/time-field";
Features
- Times can optionally include a time zone. All modifications follow time zone rules such as daylight saving time.
- Support for locale-specific formatting, number systems, hour cycles, and right-to-left layout.
- Each time unit is displayed as an individually focusable and editable segment, which allows users an easy way to edit times using the keyboard, in any format and locale.
- Time segments are editable using an easy to use numeric keypad, and all interactions are accessible using touch-based screen readers.
- Can be controlled or uncontrolled.
- Integrates with HTML forms.
Anatomy
The time field consists of:
- TimeField: The root container for the time field.
- TimeField.Label: The label that gives the user information on the time field.
- TimeField.Field: The container for the segments.
- TimeField.Segment: The component that represents a unit of a time.
- TimeField.Description: The description that gives the user more information on the time field.
- TimeField.ErrorMessage: The error message that gives the user information about how to fix a validation error on the time field.
- TimeField.HiddenInput: The native html input that is visually hidden in the time field.
tsx<TimeField><TimeField.Label /><TimeField.Field><TimeField.Segment /></TimeField.Field><TimeField.Description /><TimeField.ErrorMessage /><TimeField.HiddenInput /></TimeField>
tsx<TimeField><TimeField.Label /><TimeField.Field><TimeField.Segment /></TimeField.Field><TimeField.Description /><TimeField.ErrorMessage /><TimeField.HiddenInput /></TimeField>
Example
Usage
Default Value
A TimeField displays a placeholder by default. An initial, uncontrolled value can be provided to the TimeField using the defaultValue prop.
Time values are provided using objects in the @internationalized/date package. This library handles correct international date and time manipulation across calendars, time zones, and other localization concerns.
tsximport { Time } from "@internationalized/date";<TimeField defaultValue={new Time(11, 45)}><TimeField.Field>{(segment) => (<TimeField.Segment segment={segment()} />)}</TimeField.Field></TimeField>
tsximport { Time } from "@internationalized/date";<TimeField defaultValue={new Time(11, 45)}><TimeField.Field>{(segment) => (<TimeField.Segment segment={segment()} />)}</TimeField.Field></TimeField>
Controlled Value
The value prop can be used to make the value controlled. The onChange event is fired when the time value changes.
Selected time: 9:45 AM
tsximport { createSignal } from "solid-js";import { createDateFormatter } from "@kobalte/core/i18n";import { getLocalTimeZone, Time, toCalendarDateTime, today } from "@internationalized/date";function ControlledValueExample() {const [value, setValue] = createSignal(new Time(9, 45));const dateFormatter = createDateFormatter({hour12: true,timeStyle: "short",});return (<><TimeField value={value()} onChange={setValue}><TimeField.Field>{segment => <TimeField.Segment segment={segment()} />}</TimeField.Field></TimeField><p>Selected time:{" "}{value()? dateFormatter().format(toCalendarDateTime(today(getLocalTimeZone()), value()).toDate(getLocalTimeZone()),): "––"}</p></>);}
tsximport { createSignal } from "solid-js";import { createDateFormatter } from "@kobalte/core/i18n";import { getLocalTimeZone, Time, toCalendarDateTime, today } from "@internationalized/date";function ControlledValueExample() {const [value, setValue] = createSignal(new Time(9, 45));const dateFormatter = createDateFormatter({hour12: true,timeStyle: "short",});return (<><TimeField value={value()} onChange={setValue}><TimeField.Field>{segment => <TimeField.Segment segment={segment()} />}</TimeField.Field></TimeField><p>Selected time:{" "}{value()? dateFormatter().format(toCalendarDateTime(today(getLocalTimeZone()), value()).toDate(getLocalTimeZone()),): "––"}</p></>);}
Time Zones
TimeField is time zone aware when a ZonedDateTime object is provided as the value. In this case, the time zone abbreviation is displayed, and time zone concerns such as daylight saving time are taken into account when the value is manipulated.
@internationalized/date includes functions for parsing strings in multiple formats into ZonedDateTime objects.
tsximport { parseZonedDateTime } from "@internationalized/date";<TimeField defaultValue={parseZonedDateTime("2022-11-07T00:45[America/Los_Angeles]")}><TimeField.Field>{segment => <TimeField.Segment segment={segment()} />}</TimeField.Field></TimeField>;
tsximport { parseZonedDateTime } from "@internationalized/date";<TimeField defaultValue={parseZonedDateTime("2022-11-07T00:45[America/Los_Angeles]")}><TimeField.Field>{segment => <TimeField.Segment segment={segment()} />}</TimeField.Field></TimeField>;
Granularity
The granularity prop allows you to control the smallest unit that is displayed by a TimeField. By default, times are displayed with "minute" granularity. More granular time values can be displayed by setting the granularity prop to "second".
tsx<TimeField granularity="second"><TimeField.Field>{segment => <TimeField.Segment segment={segment()} />}</TimeField.Field></TimeField>
tsx<TimeField granularity="second"><TimeField.Field>{segment => <TimeField.Segment segment={segment()} />}</TimeField.Field></TimeField>
Minimum and Maximum Values
The minValue and maxValue props can be used to perform builtin validation. This marks the time field as invalid using ARIA if the user enters an invalid time.
tsx<TimeField defaultValue={new Time(9, 45)} minValue={new Time(9)} maxValue={new Time(17)}><TimeField.Field>{segment => <TimeField.Segment segment={segment()} />}</TimeField.Field><TimeField.ErrorMessage>Select time between 9 AM and 5 PM.</TimeField.ErrorMessage></TimeField>
tsx<TimeField defaultValue={new Time(9, 45)} minValue={new Time(9)} maxValue={new Time(17)}><TimeField.Field>{segment => <TimeField.Segment segment={segment()} />}</TimeField.Field><TimeField.ErrorMessage>Select time between 9 AM and 5 PM.</TimeField.ErrorMessage></TimeField>
Placeholder Value
When no value is set, a placeholder is shown. The format of the placeholder is influenced by the granularity and placeholderValue props. placeholderValue also controls the default values of each segment when the user first interacts with them, e.g. using the up and down arrow keys. By default, the placeholderValue is midnight.
tsx<TimeField placeholderValue={new Time(9)}><TimeField.Field>{segment => <TimeField.Segment segment={segment()} />}</TimeField.Field></TimeField>
tsx<TimeField placeholderValue={new Time(9)}><TimeField.Field>{segment => <TimeField.Segment segment={segment()} />}</TimeField.Field></TimeField>
Hide Time Zone
When a ZonedDateTime object is provided as the value of a TimeField, the time zone abbreviation is displayed by default. It can be hidden using the hideTimeZone prop.
tsx<TimeField defaultValue={parseZonedDateTime("2022-11-07T00:45[America/Los_Angeles]")} hideTimeZone><TimeField.Field>{segment => <TimeField.Segment segment={segment()} />}</TimeField.Field></TimeField>
tsx<TimeField defaultValue={parseZonedDateTime("2022-11-07T00:45[America/Los_Angeles]")} hideTimeZone><TimeField.Field>{segment => <TimeField.Segment segment={segment()} />}</TimeField.Field></TimeField>
Hour Cycle
By default, TimeField displays times in either 12 or 24 hour format depending on the user's locale. This can be overridden using the hourCycle prop.
tsx<TimeField hourCycle={24}><TimeField.Field>{segment => <TimeField.Segment segment={segment()} />}</TimeField.Field></TimeField>
tsx<TimeField hourCycle={24}><TimeField.Field>{segment => <TimeField.Segment segment={segment()} />}</TimeField.Field></TimeField>
Description
The TimeField.Description component can be used to associate additional help text with a time field.
tsx<TimeField><TimeField.Label>Time</TimeField.Label><TimeField.Field>{segment => <TimeField.Segment segment={segment()} />}</TimeField.Field><TimeField.Description>Select a meeting time.</TimeField.Description></TimeField>
tsx<TimeField><TimeField.Label>Time</TimeField.Label><TimeField.Field>{segment => <TimeField.Segment segment={segment()} />}</TimeField.Field><TimeField.Description>Select a meeting time.</TimeField.Description></TimeField>
Error message
The TimeField.ErrorMessage component can be used to help the user fix a validation error. It should be combined with the validationState prop to semantically mark the time field as invalid for assistive technologies.
By default, it will render only when the validationState prop is set to invalid, use the forceMount prop to always render the error message (ex: for usage with animation libraries).
tsximport { createSignal } from "solid-js";function ErrorMessageExample() {const [value, setValue] = createSignal(undefined);return (<TimeFieldvalue={value()}onChange={setValue}validationState={value() === undefined ? "invalid" : "valid"}><TimeField.Label>Time</TimeField.Label><TimeField.Field>{segment => <TimeField.Segment segment={segment()} />}</TimeField.Field><TimeField.ErrorMessage>Please select a time.</TimeField.ErrorMessage></TimeField>);}
tsximport { createSignal } from "solid-js";function ErrorMessageExample() {const [value, setValue] = createSignal(undefined);return (<TimeFieldvalue={value()}onChange={setValue}validationState={value() === undefined ? "invalid" : "valid"}><TimeField.Label>Time</TimeField.Label><TimeField.Field>{segment => <TimeField.Segment segment={segment()} />}</TimeField.Field><TimeField.ErrorMessage>Please select a time.</TimeField.ErrorMessage></TimeField>);}
HTML forms
The name prop can be used for integration with HTML forms.
tsxfunction HTMLFormExample() {const onSubmit = (e: SubmitEvent) => {// handle form submission.};return (<form onSubmit={onSubmit}><TimeField name="time"><TimeField.Field>{segment => <TimeField.Segment segment={segment()} />}</TimeField.Field><TimeField.HiddenInput /></TimeField><div><button type="reset">Reset</button><button type="submit">Submit</button></div></form>);}
tsxfunction HTMLFormExample() {const onSubmit = (e: SubmitEvent) => {// handle form submission.};return (<form onSubmit={onSubmit}><TimeField name="time"><TimeField.Field>{segment => <TimeField.Segment segment={segment()} />}</TimeField.Field><TimeField.HiddenInput /></TimeField><div><button type="reset">Reset</button><button type="submit">Submit</button></div></form>);}
API Reference
TimeField
TimeField is equivalent to the Root import from @kobalte/core/time-field.
| Prop | Description |
|---|---|
| value | TimeValue The current value (controlled). |
| defaultValue | TimeValue The default value (uncontrolled). |
| onChange | (value: MappedTimeValue<TimeValue>) => void Handler that is called when the value changes. |
| hourCycle | 12 | 24 Whether to display the time in 12 or 24-hour format. By default, this is determined by the user's locale. |
| granularity | 'hour' | 'minute' | 'second' Determines the smallest unit that is displayed in the time field. Defaults to "minute". |
| hideTimeZone | boolean Whether to hide the time zone abbreviation. |
| shouldForceLeadingZeros | boolean Whether to always show leading zeros in the hour field. By default, this is determined by the user's locale. |
| placeholderValue | TimeValue A placeholder time that influences the format of the placeholder shown when no value is selected. Defaults to 12:00 AM or 00:00 depending on the hour cycle. |
| minValue | TimeValue The minimum allowed time that a user may select. |
| maxValue | TimeValue The maximum allowed time that a user may select. |
| name | string The name of the time field. Submitted with its owning form as part of a name/value pair. |
| validationState | 'valid' | 'invalid' Whether the time field should display its "valid" or "invalid" visual styling. |
| required | boolean Whether the time field is required. |
| disabled | boolean Whether the time field is disabled. |
| readOnly | boolean Whether the time field is read only. |
| translations | TimeFieldIntlTranslations The localized strings of the component. |
| Data attribute | Description |
|---|---|
| data-valid | Present when the time field is valid according to the validation rules. |
| data-invalid | Present when the time field is invalid according to the validation rules. |
| data-required | Present when the time field is required. |
| data-disabled | Present when the time field is disabled. |
| data-readonly | Present when the time field is read only. |
TimeField.Label, TimeField.Field, TimeField.Segment, TimeField.Description and TimeField.ErrorMesssage share the same data-attributes.
TimeField.Segment
| Prop | Description |
|---|---|
| segment | TimeSegment A segment of the time field. |
| Data attribute | Description |
|---|---|
| data-separator | Present when the segment is a separator. |
| data-type | Always present. |
| data-placeholder | Present when the segment's value is a placeholder. |
TimeField.ErrorMessage
| Prop | Description |
|---|---|
| forceMount | boolean Used to force mounting when more control is needed. Useful when controlling animation with SolidJS animation libraries. |
Rendered elements
| Component | Default rendered element |
|---|---|
TimeField | div |
TimeField.Label | span |
TimeField.Field | div |
TimeField.Segment | div |
TimeField.Description | div |
TimeField.ErrorMessage | div |
TimeField.HiddenInput | input |
Accessibility
Keyboard Interactions
| Key | Description |
|---|---|
| Backspace | Deletes the value in the current segment and moves focus to the previous segment when empty. |
| Delete | Deletes the value in the current segment and moves focus to the previous segment when empty. |
| ArrowRight | Moves focus to the next segment. |
| ArrowLeft | Moves focus to the previous segment. |
| ArrowUp | Increments the given segment. Upon reaching the minimum or maximum value, the value wraps around to the opposite limit. |
| ArrowDown | Decrements the given segment. Upon reaching the minimum or maximum value, the value wraps around to the opposite limit. |
| PageUp | Increments the given segment by a larger amount, rounding it to the nearest increment. The amount to increment by depends on the segment, for example 2 hours, 15 minutes, and 15 seconds. Upon reaching the minimum or maximum value, the value wraps around to the opposite limit. |
| PageDown | Decrements the given segment by a larger amount, rounding it to the nearest decrement. The amount to decrement by depends on the segment, for example 2 hours, 15 minutes, and 15 seconds. Upon reaching the minimum or maximum value, the value wraps around to the opposite limit. |
| Home | Decrements the given segment by the segment's minimum value. |
| End | Increments the given segment by the segment's maximum value. |