<TimePicker
className="w-40"
aria-label="Event time"
defaultValue={new Time(9, 30)}
>
<InputGroup>
<DateInput />
<InputGroupAddon>
<Button
variant="default"
size="sm"
isIconOnly
aria-label="Choose time"
>
<ClockIcon />
</Button>
</InputGroupAddon>
</InputGroup>
<Popover>
<DialogContent>
<TimePickerColumns />
</DialogContent>
</Popover>
</TimePicker>Installation
npx shadcn@latest add @dotui/time-pickerUsage
Use time pickers to allow users to select a time using a field and a scrollable column popover.
import { ClockIcon } from 'lucide-react'
import { Button } from '@/components/ui/button'
import { DialogContent } from '@/components/ui/dialog'
import { Label } from '@/components/ui/field'
import { DateInput, InputGroup, InputGroupAddon } from '@/components/ui/input'
import { Popover } from '@/components/ui/popover'
import { TimePicker, TimePickerColumns } from '@/components/ui/time-picker'<TimePicker>
<Label>Time</Label>
<InputGroup>
<DateInput />
<InputGroupAddon>
<Button variant="default" size="sm" isIconOnly aria-label="Choose time">
<ClockIcon />
</Button>
</InputGroupAddon>
</InputGroup>
<Popover>
<DialogContent>
<TimePickerColumns />
</DialogContent>
</Popover>
</TimePicker>Anatomy
There is no React Aria TimePicker, so it's composed from field and overlay primitives: TimePicker wraps a labeled InputGroup (the editable DateInput plus a Button trigger in an InputGroupAddon) and a Popover whose DialogContent renders the scrollable TimePickerColumns. Description and FieldError are optional field slots.
<TimePicker>
<Label />
<InputGroup>
<DateInput />
<InputGroupAddon>
<Button />
</InputGroupAddon>
</InputGroup>
<Description />
<FieldError />
<Popover>
<DialogContent>
<TimePickerColumns />
</DialogContent>
</Popover>
</TimePicker>Value
The value is an @internationalized/date Time object. Use defaultValue for uncontrolled state, or value with onChange to control it. Bound the selectable range with minValue and maxValue.
import { Time } from '@internationalized/date'
const [value, setValue] = React.useState(new Time(9, 30))
<TimePicker value={value} onChange={setValue}>
{/* ... */}
</TimePicker>Granularity
granularity ("hour", "minute", or "second") controls both the editable segments and which scrollable columns render. hourCycle switches between 12- and 24-hour display.
<TimePicker granularity="second" hourCycle={24}>
{/* ... */}
</TimePicker>Open state
The popover is uncontrolled by default. Open it initially with defaultOpen, or control it with isOpen and onOpenChange.
<TimePicker isOpen={isOpen} onOpenChange={setIsOpen}>
{/* ... */}
</TimePicker>Examples
Basic
With Label & Description
Granularity
Hour Cycle
API Reference
TimePicker
A time picker combines a TimeField and a scrollable time-column popover to allow users to enter or select a time value.
| Prop | Type | Default | |
|---|---|---|---|
"hour" | "minute" | "second" | 'minute' | ||
boolean | — | ||
12 | 24 | — | ||
boolean | — | ||
boolean | — | ||
T | — | ||
boolean | — | ||
T | null | — | ||
T | null | — | ||
function | — | ||
Last updated on 7/21/2026