Kobalte.v0.13.11

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

ts
import { TimeField } from "@kobalte/core/time-field";
// or
import { Root, Label, ... } from "@kobalte/core/time-field";
ts
import { TimeField } from "@kobalte/core/time-field";
// or
import { 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

Event time

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.

tsx
import { Time } from "@internationalized/date";
<TimeField defaultValue={new Time(11, 45)}>
<TimeField.Field>
{(segment) => (
<TimeField.Segment segment={segment()} />
)}
</TimeField.Field>
</TimeField>
tsx
import { 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

tsx
import { 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>
</>
);
}
tsx
import { 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.

tsx
import { parseZonedDateTime } from "@internationalized/date";
<TimeField defaultValue={parseZonedDateTime("2022-11-07T00:45[America/Los_Angeles]")}>
<TimeField.Field>{segment => <TimeField.Segment segment={segment()} />}</TimeField.Field>
</TimeField>;
tsx
import { 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.

Time
Select a meeting time.
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).

Time
Please select a time.
tsx
import { createSignal } from "solid-js";
function ErrorMessageExample() {
const [value, setValue] = createSignal(undefined);
return (
<TimeField
value={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>
);
}
tsx
import { createSignal } from "solid-js";
function ErrorMessageExample() {
const [value, setValue] = createSignal(undefined);
return (
<TimeField
value={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.

tsx
function 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>
);
}
tsx
function 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.

PropDescription
valueTimeValue
The current value (controlled).
defaultValueTimeValue
The default value (uncontrolled).
onChange(value: MappedTimeValue<TimeValue>) => void
Handler that is called when the value changes.
hourCycle12 | 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".
hideTimeZoneboolean
Whether to hide the time zone abbreviation.
shouldForceLeadingZerosboolean
Whether to always show leading zeros in the hour field. By default, this is determined by the user's locale.
placeholderValueTimeValue
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.
minValueTimeValue
The minimum allowed time that a user may select.
maxValueTimeValue
The maximum allowed time that a user may select.
namestring
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.
requiredboolean
Whether the time field is required.
disabledboolean
Whether the time field is disabled.
readOnlyboolean
Whether the time field is read only.
translationsTimeFieldIntlTranslations
The localized strings of the component.
Data attributeDescription
data-validPresent when the time field is valid according to the validation rules.
data-invalidPresent when the time field is invalid according to the validation rules.
data-requiredPresent when the time field is required.
data-disabledPresent when the time field is disabled.
data-readonlyPresent 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

PropDescription
segmentTimeSegment
A segment of the time field.
Data attributeDescription
data-separatorPresent when the segment is a separator.
data-typeAlways present.
data-placeholderPresent when the segment's value is a placeholder.

TimeField.ErrorMessage

PropDescription
forceMountboolean
Used to force mounting when more control is needed. Useful when controlling animation with SolidJS animation libraries.

Rendered elements

ComponentDefault rendered element
TimeFielddiv
TimeField.Labelspan
TimeField.Fielddiv
TimeField.Segmentdiv
TimeField.Descriptiondiv
TimeField.ErrorMessagediv
TimeField.HiddenInputinput

Accessibility

Keyboard Interactions

KeyDescription
BackspaceDeletes the value in the current segment and moves focus to the previous segment when empty.
DeleteDeletes the value in the current segment and moves focus to the previous segment when empty.
ArrowRightMoves focus to the next segment.
ArrowLeftMoves focus to the previous segment.
ArrowUpIncrements the given segment. Upon reaching the minimum or maximum value, the value wraps around to the opposite limit.
ArrowDownDecrements the given segment. Upon reaching the minimum or maximum value, the value wraps around to the opposite limit.
PageUpIncrements 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.
PageDownDecrements 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.
HomeDecrements the given segment by the segment's minimum value.
EndIncrements the given segment by the segment's maximum value.