Time Picker

A time picker combines a time field and a scrollable column popover to allow users to select a time.

930AM
<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-picker

Usage

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

930AM

With Label & Description

Event time
––––AM
Please select a time.

Granularity

hour
11AM
minute
1145AM
second
114530AM

Hour Cycle

12-hour
230PM
24-hour
1430

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.

PropType
"hour" | "minute" | "second"
boolean
12 | 24
boolean
boolean
T
boolean
T | null
T | null
function

Last updated on 7/21/2026