/// Inputs
TimePicker
Sunken field that opens a TimeInput plus scrollable hour / minute columns in a raised overlay for point-and-click time selection.
import { TimePicker } from "@protocore/pds";Basics
The trigger shows the formatted time; opening it reveals a TimeInput for typing plus scrollable columns for browsing. Controllable via value / defaultValue / onValueChange.
12-hour, seconds & step
Set hour12 for an AM/PM clock, withSeconds for a seconds column, and minuteStep to thin the minute column to rounded slots (e.g. every 15 minutes).
When to use it
Use TimePicker when picking a rounded slot by eye is easier than typing — a booking time, an alarm. It still embeds a TimeInput for fast keyboard entry. For a bare typed field use TimeInput; to choose a date and time together use DateTimePicker.
Usage
Do
- Give the trigger an accessible name via a `Field` label or `aria-label`.
- Set `minuteStep` to the granularity your booking really supports.
- Pass a `locale` so the field value matches the surrounding UI.
- Keep the embedded TimeInput for users who would rather type than scroll.
Don't
- Don't use a 1-minute column for a coarse scheduling flow — the list becomes a wall.
- Don't leave the trigger unlabelled when no visible field label wraps it.
- Don't reformat the value in state — read the `TimeValue` from `onValueChange`.
- Don't nest it inside another popover trigger where overlays contend for focus.
Accessibility
| Keys | Action |
|---|---|
| Enter / Space | Open the overlay from the focused trigger. |
| Arrow keys | Step the embedded TimeInput's focused segment. |
| Tab | Move into the hour / minute columns. |
| Esc | Close the overlay without changing the value. |
- The overlay is a Radix Popover: portalled, dismissed on outside-click and Escape, and returns focus to the trigger on close.
- Each column is a `role="listbox"` of `role="option"` buttons with `aria-selected` on the current value.
- `invalid` sets `aria-invalid` on the trigger; the trigger exposes `aria-expanded` for its open state.
TimePicker props
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | — | |
defaultOpen | boolean | — | Initial open state in uncontrolled mode. |
defaultValue | TimeValue | null | — | Initial time in uncontrolled mode. |
disabled | boolean | — | Disable the whole control. |
hour12 | boolean | false | Use a 12-hour clock. |
invalid | boolean | — | Mark the field invalid — danger border plus `aria-invalid`. |
locale | string | — | BCP-47 locale for the formatted field value. |
minuteStep | number | 5 | Minute (and second) column step. |
onOpenChange | ((open: boolean) => void) | — | Fires when the overlay opens or closes. |
onValueChange | ((value: TimeValue | null) => void) | — | Fires with the chosen time, or `null` while incomplete. |
open | boolean | — | Controlled open state of the overlay. |
placeholder | string | Select time | Text shown when no time is selected. |
size | enum | md | Field height: `sm` (32) · `md` (36, default) · `lg` (40). |
style | CSSProperties | — | |
value | TimeValue | null | — | Controlled time. Pass `null` for no selection. |
withSeconds | boolean | false | Include a seconds column + segment. |