A field for a time of day, with separate hour, minute and (optional) second segments that follow the visitor's locale and 12 or 24 hour clock.
import { Time } from "@internationalized/date";
import { TimeField } from "@rdloom/react";
export default function TimeFieldBasicExample() {
return (
<div className="w-48">
<TimeField label="Start time" defaultValue={new Time(9, 30)} />
</div>
);
}Installation
npx rdloom add time-fieldCopies the source into src/components/rdloom. Edit it freely: rdloom upgrade merges later versions into your changes. It needs react-aria-components; add --install to install them.
Use another registry client
npx shadcn@latest add https://rdloom.vimalbhatt.com/r/time-field.jsonWorks, but without upgrade tracking.
Usage
import { TimeField } from "@rdloom/react";
<div className="w-48">
<TimeField label="Start time" defaultValue={new Time(9, 30)} />
</div>Seconds
import { Time } from "@internationalized/date";
import { TimeField } from "@rdloom/react";
export default function TimeFieldSecondsExample() {
return (
<div className="flex flex-col gap-4">
<div className="w-56">
<TimeField label="Timestamp" granularity="second" defaultValue={new Time(14, 5, 30)} />
</div>
<div className="w-48">
<TimeField label="24 hour clock" hourCycle={24} defaultValue={new Time(18, 0)} />
</div>
</div>
);
}Range
import { Time } from "@internationalized/date";
import { TimeField } from "@rdloom/react";
// minValue and maxValue make times outside opening hours invalid.
export default function TimeFieldRangeExample() {
return (
<div className="w-64">
<TimeField
label="Pickup time"
description="We are open 9:00 to 17:00."
validationBehavior="aria"
minValue={new Time(9)}
maxValue={new Time(17)}
defaultValue={new Time(20, 15)}
errorMessage="Pick a time between 9:00 and 17:00."
/>
</div>
);
}API Reference
Defined by the spec. Components also accept the props of the React Aria component they wrap.
| Prop | Type | Default |
|---|---|---|
labelrequiredVisible label, also the accessible name. | string | none |
descriptionHelp text under the field. | string | none |
errorMessageShown when the value is invalid. Leave out to use the built-in message. | string | none |
valueControlled value. | TimeValue | null | none |
defaultValueInitial value when uncontrolled. | TimeValue | null | none |
onChangeCalled with the time, or null when it is cleared. | (value: TimeValue | null) => void | none |
granularitySmallest unit shown and edited. | "hour" | "minute" | "second" | "minute" |
hourCycleForce a 12 or 24 hour clock. Leave out to follow the locale. | 12 | 24 | none |
minValueEarliest allowed time. | TimeValue | none |
maxValueLatest allowed time. | TimeValue | none |
sizeField height and text size. | "sm" | "md" | "lg" | "md" |
isDisabledPrevents interaction and dims the field. | boolean | false |
isInvalidMarks the field invalid. Leave it unset to let validation decide. | boolean | none |
isRequiredMarks the field required and adds an asterisk. | boolean | false |
Accessibility
Role group, WCAG 2.2 AA. Tested with axe and keyboard tests; screen reader checks are in the audit checklist.
Keyboard
- Left and Right arrows (or Tab) move between hour, minute and AM/PM
- Up and Down arrows change the focused segment; typing digits sets it
- Backspace clears the focused segment
Screen readers announce
- Entering announces the label, then the first segment as "hours, spin button" with its value
- Changing a segment announces the new value
- The group is announced with the full time, e.g. "9:30 AM"
What your code must do
- A labelled group of spin buttons: each segment is named (hours, minutes, AM/PM) and exposes its range
- Digits typed move to the next segment on their own
- Invalid state and the error message are linked to the field
- The focused segment is highlighted with 3:1 contrast, not only by color
Guidelines
Use it when
- Opening hours, reminders, meeting times and schedules
- Any time of day that is not tied to a date
Avoid it when
- A date and a time together: use DatePicker and TimeField side by side
- A duration, such as 90 minutes: use NumberField
Don't
- Forcing a 24 hour clock on people who use 12 hour (leave hourCycle to the locale unless you must)
- A free text field for times
Design tokens
The semantic tokens this component uses. Change them once and every component follows; see Design tokens.
--rd-color-surface-default--rd-color-surface-subtle--rd-color-border-default--rd-color-border-strong--rd-color-text-default--rd-color-text-muted--rd-color-feedback-danger--rd-color-focus-ring--rd-radius-control--rd-color-action-primary--rd-color-action-on-primary