Time Picker
Hour, minute and second columns.
Introduction
Three scrolling columns. Hover fills primary-50 and the current value fills primary-100, with a neutral-100 rule between the columns — measured from the UX4G kit.
Each column is a listbox where selection follows focus, so ↑ and ↓ change the value directly. That is the right pattern for a spinner, and it keeps each column to one tab stop rather than sixty.
For a time behind a trigger, use TimePickerField from Date Picker.
Installation
npx shadcn@latest add https://indiacn.in/r/time-picker.jsonimport { TimeColumns, TimePicker } from '@/components/ui/time-picker';Usage
const [time, setTime] = useState<ITimeValue>({ hours: 9, minutes: 30, seconds: 0 });
return <TimePicker value={time} onValueChange={setTime} showHeader />;Examples
Default
09:30:00
Chosen: 09:30:00
'use client';
import { useState } from 'react';
import { ITimeValue, TimePicker } from '@/components/ui/time-picker';
export default function Component() {
const [time, setTime] = useState<ITimeValue>({ hours: 9, minutes: 30, seconds: 0 });
return <TimePicker value={time} onValueChange={setTime} showHeader />;
}Without seconds
14:00
'use client';
import { useState } from 'react';
import { ITimeValue, TimePicker, formatTime } from '@/components/ui/time-picker';
import { Body3 } from '@/components/ui/typography';
export function TimePickerDefault() {
const [time, setTime] = useState<ITimeValue>({ hours: 9, minutes: 30, seconds: 0 });
return (
<div className='flex flex-col gap-4'>
<TimePicker value={time} onValueChange={setTime} showHeader />
<Body3 className='text-neutral-600'>Chosen: {formatTime(time, true)}</Body3>
</div>
);
}
export function TimePickerNoSeconds() {
const [time, setTime] = useState<ITimeValue>({ hours: 14, minutes: 0, seconds: 0 });
return <TimePicker value={time} onValueChange={setTime} showSeconds={false} showHeader />;
}
Accessibility
| Key | Moves |
|---|---|
| ↑ ↓ | One step, wrapping |
| PageUp PageDown | Ten steps |
| Home End | First and last value |
- Each column is a
listboxlabelled Hour, Minute or Second, and every option carriesaria-selected. - Only the current value is tabbable, so three columns are three tab stops.
- The selected fill is
primary-100withneutraltext, which holds well past 4.5:1 in both themes. - Values are zero-padded and rendered with
tabular-nums, so the columns do not jitter as they scroll.
API Reference
TimePicker
| Prop | Type | Default | Description |
|---|---|---|---|
value | ITimeValue | — | Current time |
onValueChange | (value: ITimeValue) => void | — | Fires on every change |
showSeconds | boolean | true | Renders the third column |
showHeader | boolean | false | Echoes the value above the columns |
onConfirm | () => void | — | Omit it and the Ok button is not rendered |
TimeColumns
The three columns with no card, header or footer, for composing into a larger surface. Takes value, onValueChange and showSeconds.
ITimeValue is { hours: number; minutes: number; seconds: number }. The module also exports formatTime(value, showSeconds) and toTimeValue(date).