Skip to main contentSkip to docs navigation

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.

––––AM
In your local time.
JSX
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.

9AM
93015AM
2130
JSX
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.

245PM
Current value: 14:45:00
JSX
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.

800AM
Office hours.
Between 9 AM and 5 PM.
JSX
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.

2130
٩٣٠م
JSX
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.

––––AM
JSX
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

930AM
930AM
930AM
JSX
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.

930AM
930AM
––––AM
Choose a time.
930AM
Free.
JSX
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

PropTypeDefault
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.