Time Input
Segmented React Aria time field primitive (locale-aware hour/minute/AM-PM slots) used as the trigger for Time Picker and the calendar time controls.
Time Input is the segmented clock field (TimeInputControl) shared by Time Picker and calendar time footers. Operators type or arrow through locale-aware hour / minute / AM·PM slots. Values stay plain Date — only the clock portion is read or written.
Prefer Time Picker when you need a spinner popover. Prefer Date Picker when the value is a calendar day (optionally with time).
When To Use
- Inline time typing without a popover — table cells, calendar footers, compact filters.
- The same field chrome Time Picker uses, when you own open/close yourself.
- Use Time Picker when operators should pick from column spinners.
- Use Date Picker (
withTime) when date and time belong together. - Use Time Range Picker for a start–end pair.
Features
| Area | Behavior |
|---|---|
| Value | Plain Date; onValueChange uses null for empty (never undefined) |
| Segments | React Aria hour / minute / optional second / AM·PM from hourCycle and locale |
| Surfaces | default, compact, tableCell (borderless grid cell) |
| Icon | Trailing clock, decorative; hide with showIcon={false} when a picker owns the trigger |
| Read-only | Quiet field chrome; still focusable. Host should mount Read-Only Hint |
Interactions
| Event | Behavior |
|---|---|
| Focus a segment | Caret in that slot; onFocus fires (pickers use this to open) |
| Type or arrow | Updates the focused unit; onChange / onValueChange fire together |
| Clear the field | onValueChange(null); legacy onChange may receive undefined |
readOnly | Segments stay navigable; commits are ignored |
Installing
pnpm dlx shadcn@latest add https://ui.isaacfei.com/r/time-input.jsonnpx shadcn@latest add https://ui.isaacfei.com/r/time-input.jsonyarn dlx shadcn@latest add https://ui.isaacfei.com/r/time-input.jsonbun x shadcn@latest add https://ui.isaacfei.com/r/time-input.jsonWith a namespace: npx shadcn@latest add @f-ui/time-input.
registryDependencies: https://ui.isaacfei.com/r/date-internals.json, https://ui.isaacfei.com/r/fui-i18n.json, https://ui.isaacfei.com/r/field-readonly-surface.json, https://ui.isaacfei.com/r/read-only-hint.json, shadcn label. Runtime npm: react-aria-components.
Usage
import { TimeInputControl } from "@/components/f-ui/time-input/time-input-parts/control";
<TimeInputControl
aria-label="Start time"
value={time}
onValueChange={setTime}
/>Examples
Segmented Field
Default minute granularity in the locale hour cycle. Tab between slots and type a time.
"use client";
import { useState } from "react";
import { TimeInputControl } from "@/components/f-ui/time-input/time-input-parts/control";
export function TimeInputDemo() {
const [time, setTime] = useState<Date | null>(
() => new Date(2026, 4, 21, 9, 30, 0, 0),
);
return (
<div className="max-w-xs w-full">
<TimeInputControl
aria-label="Start time"
value={time}
onValueChange={setTime}
/>
</div>
);
}12-Hour With Seconds
hourCycle={12} adds an AM·PM slot; granularity="second" adds seconds. The trailing clock stays decorative.
"use client";
import { useState } from "react";
import { TimeInputControl } from "@/components/f-ui/time-input/time-input-parts/control";
export function TimeInput12hDemo() {
const [time, setTime] = useState<Date | null>(
() => new Date(2026, 4, 21, 14, 15, 30, 0),
);
return (
<div className="max-w-xs w-full">
<TimeInputControl
aria-label="Appointment time"
value={time}
onValueChange={setTime}
hourCycle={12}
granularity="second"
/>
</div>
);
}Read-Only
readOnly keeps the field box and focus ring but blocks commits. This demo mounts Read-Only Hint beside the control — Time Input wires aria-describedby when id is set, but does not render the hint itself.
"use client";
import { ReadOnlyHint } from "@/components/f-ui/internals/read-only-hint";
import { TimeInputControl } from "@/components/f-ui/time-input/time-input-parts/control";
const CONTROL_ID = "posted-at";
export function TimeInputReadOnlyDemo() {
return (
<div className="max-w-xs w-full">
<ReadOnlyHint controlId={CONTROL_ID} />
<TimeInputControl
id={CONTROL_ID}
aria-label="Posted at"
value={new Date(2026, 4, 21, 9, 30, 0, 0)}
readOnly
/>
</div>
);
}Composition
TimeInputControl
├── field-box (surface chrome)
│ ├── ClockIcon? (showIcon, trailing, aria-hidden)
│ └── TimeField (React Aria)
│ └── DateInput (hour / minute / second / AM·PM segments)
└── I18nProvider? (when a React Aria locale tag is resolved)API Reference
Props
Extends the segmented time field options.
| Prop | Type | Default | Description |
|---|---|---|---|
value | Date | null | — | Clock portion of a Date. Empty is null. |
onValueChange | (time: Date | null) => void | — | Fires with null when cleared. Prefer this over onChange. |
onChange | (time: Date | undefined) => void | — | Legacy companion; may receive undefined on clear. |
onFocus | () => void | — | A time segment gained focus. |
onBlur | () => void | — | Field blurred. |
granularity | "minute" | "second" | "minute" | Smallest editable unit. |
hourCycle | 12 | 24 | locale | Forces 12-hour (AM·PM) or 24-hour slots. |
minValue / maxValue | Date | — | Time-of-day bounds. |
disabled | boolean | — | Cannot operate. |
readOnly | boolean | — | Navigable, not operable. Ignored while disabled. |
isInvalid | boolean | — | Invalid chrome. |
invalidTitle | string | — | Native title on the outer wrapper. |
locale | string | i18n provider | React Aria locale for segments. |
id | string | — | Control id; with readOnly, described-by includes {id}-readonly. |
aria-label / aria-labelledby / aria-describedby | string | — | Passed to the TimeField. |
surface | "default" | "compact" | "tableCell" | "default" | tableCell is borderless for always-live grid cells. |
showIcon | boolean | true | Trailing decorative clock. |
className | string | — | Outer wrapper. |
Slots
| Slot | Element |
|---|---|
shell | Inner field-box (data-slot="field-box") |
input | Segmented DateInput |
icon | Trailing clock wrapper |
Pass via classNames={{ shell, input, icon }}.
See Also
- Time Picker — this field plus spinner popover
- Time Range Picker
- Date Picker
- Date Range Picker
- Calendar
- Read-Only Hint