Time Field
A time of day typed or stepped segment by segment, in the locale's format, with a granularity, 12 or 24 hours, and a range.
Overview
TimeField is a time of day, built on React Aria's useTimeField. It renders one editable segment
per unit (the hour, the minute, AM or PM), as the field of a
Datepicker renders a date: type a number into a segment, or
step it with the Up and Down arrow keys. Like the other form fields, it takes label, help and
the validation props, and renders a FormLabel, FormHelp and FormFeedback wired to it.
import { TimeField } from '@chassis-ui/react'
export const Example = () => <TimeField help="In your local time." label="Start" />The field is a .form-input that holds the segments, so it takes chassis-css's sizes and states.
The segments' own styles are the date pickers', in @chassis-ui/react/style.css (see
Theming).
Granularity and hour cycle
granularity sets the smallest unit: hour, minute (the default) or second. The locale decides
between 12 and 24 hours; hourCycle sets it, and shouldForceLeadingZeros writes 09 for 9.
import { Time } from '@internationalized/date'
import { TimeField } from '@chassis-ui/react'
export const Example = () => (
<>
<TimeField defaultValue={new Time(9)} granularity="hour" label="Hour" />
<TimeField defaultValue={new Time(9, 30, 15)} granularity="second" label="Second" />
<TimeField defaultValue={new Time(21, 30)} hourCycle={24} label="24 hours" />
</>
)Value
A value is a Time from @internationalized/date,
or a CalendarDateTime or ZonedDateTime whose date the field keeps. onChange receives it once
every segment has a value, and null once every segment is empty; a field emptied only in part
keeps its last value. With placeholderValue, an empty
field starts its segments from that time. Pass value and onChange to control the value, or
defaultValue to let the component manage it.
import { useState } from 'react'
import { Time } from '@internationalized/date'
import { TimeField, type TimeFieldProps } from '@chassis-ui/react'
export const Example = () => {
const [value, setValue] = useState<TimeFieldProps['value']>(new Time(14, 45))
return (
<TimeField
help={`Current value: ${value ? value.toString() : 'empty'}`}
label="Reminder"
onChange={setValue}
value={value}
/>
)
}Range
minValue and maxValue bound the time. A time outside them shows the field as invalid, with its
invalidFeedback, and marks the segments invalid for assistive technology.
import { Time } from '@internationalized/date'
import { TimeField } from '@chassis-ui/react'
export const Example = () => (
<TimeField
defaultValue={new Time(8)}
help="Office hours."
invalidFeedback="Between 9 AM and 5 PM."
label="Meeting"
maxValue={new Time(17)}
minValue={new Time(9)}
/>
)Locale
The segments, their order and the AM/PM marker follow the locale: the browser's, or the one an
I18nProvider sets. A right-to-left locale
keeps the time itself left to right, as it is written.
import { Time } from '@internationalized/date'
import { I18nProvider, TimeField } from '@chassis-ui/react'
export const Example = () => (
<>
<I18nProvider locale="de-DE">
<TimeField defaultValue={new Time(21, 30)} label="Beginn" />
</I18nProvider>
<I18nProvider locale="ar-EG">
<div dir="rtl">
<TimeField defaultValue={new Time(21, 30)} label="البداية" />
</div>
</I18nProvider>
</>
)In a form
With name, the field submits its value as an ISO 8601 time, 21:30:00, from a hidden input.
form links it to a form elsewhere on the page. Resetting the form restores defaultValue.
With required, an empty field holds its form back from submitting: the first segment takes focus
and the field shows as invalid, with its invalidFeedback, until it has a time or the form is
reset. invalid, once set, and valid decide how the field looks instead. A disabled or
read-only field holds nothing back.
import { useState } from 'react'
import { Button, Stack, TimeField } from '@chassis-ui/react'
export const Example = () => {
const [submitted, setSubmitted] = useState('')
return (
<form
onSubmit={(event) => {
event.preventDefault()
setSubmitted(JSON.stringify(Object.fromEntries(new FormData(event.currentTarget))))
}}
>
<Stack direction="vertical" gap="md" style={{ maxWidth: '20rem' }}>
<TimeField
help={submitted ? `Submitted: ${submitted}` : undefined}
label="Start"
name="start"
/>
<Button type="submit">Submit</Button>
</Stack>
</form>
)
}Sizing
import { Time } from '@internationalized/date'
import { TimeField } from '@chassis-ui/react'
export const Example = () => (
<>
<TimeField aria-label="Small time field" defaultValue={new Time(9, 30)} size="sm" />
<TimeField aria-label="Default time field" defaultValue={new Time(9, 30)} />
<TimeField aria-label="Large time field" defaultValue={new Time(9, 30)} size="lg" />
</>
)States
disabled and readOnly keep the time from changing; a disabled field submits nothing. invalid
and valid color the field and show invalidFeedback or validFeedback.
import { Time } from '@internationalized/date'
import { TimeField } from '@chassis-ui/react'
export const Example = () => (
<>
<TimeField defaultValue={new Time(9, 30)} disabled label="Disabled" />
<TimeField defaultValue={new Time(9, 30)} label="Read only" readOnly />
<TimeField invalid invalidFeedback="Choose a time." label="Invalid" />
<TimeField defaultValue={new Time(9, 30)} label="Valid" valid validFeedback="Free." />
</>
)Accessibility
The field is a group named by its label. Each segment is a spin button named by its unit and the label ("hour, Start"), and Tab moves between them. Once a value is set, the group is described by the whole time as well as by its help and feedback.
API
TimeField
| Prop | Type | Default |
|---|---|---|
aria-label? | string | — |
An accessible label for the field, used when there's no visible label. | ||
aria-labelledby? | string | — |
| Identifies a visible element that labels the field. | ||
autoFocus? | boolean | — |
| Focus the first segment when the field mounts. | ||
className? | string | — |
| A string of all className you want applied to the component. | ||
defaultValue? | TimeValue | null | — |
| The value of the field, uncontrolled. | ||
disabled? | boolean | — |
| Toggle the disabled state for the component. | ||
form? | string | — |
| The id of a form elsewhere on the page that the field belongs to. | ||
granularity? | "hour" | "minute" | "second" | 'minute' |
| The smallest unit shown and edited. | ||
help? | ReactNode | — |
| A description for the field, rendered below it. | ||
hideTimeZone? | boolean | — |
Hide the time zone of a ZonedDateTime value. | ||
hourCycle? | 12 | 24 | — |
| Show 12 or 24 hours. Defaults to the locale's. | ||
invalid? | boolean | — |
| Set component validation state to invalid. | ||
invalidFeedback? | ReactNode | — |
An error message for the field, rendered below it when invalid is set, and after a submit
that an empty required field held back. | ||
label? | ReactNode | — |
The field's caption, rendered as a FormLabel that names the field. | ||
maxValue? | TimeValue | null | — |
| The latest time. A later one entered marks the field invalid. | ||
minValue? | TimeValue | null | — |
| The earliest time. An earlier one entered marks the field invalid. | ||
name? | string | — |
The name the value is submitted under with a form, as an ISO 8601 time (09:30:00). | ||
onChange? | ((value: TimeValue | null) => void) | — |
Handler that is called when the value changes: once every segment has a value, and with
null once every segment is empty. A partly emptied field keeps its last value. | ||
placeholderValue? | TimeValue | — |
The time the segments start from when the field is empty, such as new Time(9). It also
sets the type of value onChange receives. | ||
readOnly? | boolean | — |
| Toggle the readonly state for the component. | ||
required? | boolean | — |
Toggle the required state for the component. An empty required field holds its form back
from submitting, takes focus and shows as invalid, with invalidFeedback, until it has a
value or the form is reset. invalid, once set, and valid decide how it looks instead. | ||
shouldForceLeadingZeros? | boolean | — |
Show a leading zero on the hour, as 09:30 rather than 9:30, whatever the locale does. | ||
size? | "sm" | "lg" | — |
| Size the component sm or lg. | ||
valid? | boolean | — |
| Set component validation state to valid. | ||
validFeedback? | ReactNode | — |
A success message for the field, rendered below it when valid is set. | ||
value? | TimeValue | null | — |
The value of the field, controlled: a Time, or a CalendarDateTime or ZonedDateTime
whose date is kept. null for an empty field. | ||