Time Picker
Single-time picker with integrated segmented field, clock icon, and popover time spinner with plain Date values.
Time Picker combines a segmented time field (React Aria hour/minute/AM·PM slots) and a clock icon inside one bordered shell, with column spinners in a popover. Values stay plain Date — only the clock portion is read or written.
Interactions
| Event | Behavior |
|---|---|
| Focus a time segment | Does not open the spinner popover (open via clock trigger). |
| Click the clock icon | Toggles the popover open or closed. |
| Select or type a time | Updates the value (or the draft when needConfirm). |
| Press Now | Sets the current time. |
| Escape or click outside | Closes the popover. |
Design guide
- Picker over native — Prefer this component (or Time Input for inline typing) over
type="time"so styling stays on your design tokens. - Format drives columns — Set
format(e.g.HH:mm:ss) to control which spinner columns appear;use12Hoursswitches the default 12h template. - Step for booking — Use
step={{ minute: 15 }}(or hour/second) to snap spinner options to appointment slots. - Business hours — Use
disabledTimeto grey out or hide hours/minutes/seconds outside allowed windows. - Select commits by default — Spinner selection commits immediately; set
needConfirmwhen the footer OK button should apply the draft.
Installing
pnpm dlx shadcn@latest add https://ui.isaacfei.com/r/time-picker.jsonUsage
import { useState } from "react";
import { TimePicker } from "@/components/f-ui/time-picker/time-picker";
export function Example() {
const [time, setTime] = useState<Date | null>(null);
return (
<TimePicker
label="Start time"
value={time}
onChange={(next) => setTime(next ?? null)}
/>
);
}Embed only the field (no label) via TimePickerFieldControl — used inside calendar footers and tables:
import { TimePickerFieldControl } from "@/components/f-ui/time-picker/time-picker";Examples
Basic
Click the clock icon or focus a segment to open the spinner.
"use client";
import { useState } from "react";
import { TimePicker } from "@/components/f-ui/time-picker/time-picker";
export function TimePickerDemo() {
const [time, setTime] = useState<Date | null>(
() => new Date(2026, 4, 21, 9, 30, 0, 0),
);
return (
<div className="max-w-xs w-full">
<TimePicker
label="Meeting time"
value={time}
onChange={(next) => setTime(next ?? null)}
description="Click the clock icon or focus a segment to open the spinner."
/>
</div>
);
}12-Hour With Seconds
12-hour clock with second precision.
"use client";
import { useState } from "react";
import { TimePicker } from "@/components/f-ui/time-picker/time-picker";
export function TimePicker12hDemo() {
const [time, setTime] = useState<Date | null>(
() => new Date(2026, 4, 21, 14, 5, 30, 0),
);
return (
<div className="max-w-xs w-full">
<TimePicker
label="Reminder"
value={time}
onChange={(next) => setTime(next ?? null)}
use12Hours
format="hh:mm:ss a"
description="12-hour clock with second precision."
/>
</div>
);
}Step + Business Hours
15-minute slots between 9:00 and 18:00.
"use client";
import { useState } from "react";
import { TimePicker } from "@/components/f-ui/time-picker/time-picker";
function businessHoursDisabledTime() {
return {
hours: () =>
Array.from({ length: 24 }, (_, hour) => hour).filter(
(hour) => hour < 9 || hour > 18,
),
};
}
export function TimePickerStepDemo() {
const [time, setTime] = useState<Date | null>(
() => new Date(2026, 4, 21, 10, 0, 0, 0),
);
return (
<div className="max-w-xs w-full">
<TimePicker
label="Booking slot"
value={time}
onChange={(next) => setTime(next ?? null)}
step={{ minute: 15 }}
disabledTime={businessHoursDisabledTime}
description="15-minute slots between 9:00 and 18:00."
/>
</div>
);
}API Reference
| Prop | Type | Default |
|---|---|---|
value | Date | null | — |
onChange | (time: Date | undefined) => void | — |
format | string | HH:mm or hh:mm a |
use12Hours | boolean | false |
step | { hour?, minute?, second? } | 1 per unit |
disabledTime | (current: Date) => { hours?, minutes?, seconds? } | — |
showNow | boolean | true |
needConfirm | boolean | false |
changeOnScroll | boolean | false |
minValue / maxValue | Date | time-of-day bounds |
disabled | boolean | false |
isInvalid | boolean | false |
label | ReactNode | — |
description / errorMessage | ReactNode | — |
locale | string | i18n provider |
classNames | { root?, field?, shell?, … } | — |
value / onChange use Date for compatibility with date pickers; only the clock portion is read or written (normalized to today in the local timezone).
Date Range Picker
Preline-style range picker with integrated segmented start/end field, calendar icon, and optional presets, clear action, time, and confirmable mode.
Time Range Picker
Range picker with integrated segmented start/end field, dual time spinners, and optional confirm flow using plain Date tuples.