Forms · astro-ui · TimePickerNew

TimePickerJS

Time field with four interaction patterns: slot list, native input, scroll-drum wheel, and circular clock.

TimePicker covers every time-entry scenario with a single component. variant="select" builds a slot list from step — the shape appointment forms need. variant="input" hands off to the platform picker. variant="wheel" renders a scroll-snap column drum — the mobile-native feel on desktop. variant="clock" renders a circular clock face where you tap the hour hand, then the minute hand. All four write the same HH:mm value into a hidden form input, so the form contract never changes.

Features

  • Four variants: `select` slots, native `input`, scroll `wheel`, circular `clock`
  • Wheel: infinite-scroll snap drums with pointer drag, momentum, and mouse wheel
  • Clock: SVG clock face — tap to set hour then minute; auto-advances between steps
  • 24-hour and 12-hour (AM/PM) mode for both `wheel` and `clock`
  • All variants write a hidden `HH:mm` input — same form contract everywhere
  • `step`, `min`, and `max` bound the available slots (select/wheel)
  • Labels formatted with `Intl` — 24-hour or 12-hour via `hour12`
  • 3 sizes, invalid state, disabled and required support

Usage

---
import { TimePicker, Label } from "astro-ui";
---

<Label for="slot">Drop-off</Label>
<TimePicker id="slot" name="slot" step={30} min="09:00" max="17:00"/>

<!-- Wheel -->
<TimePicker name="appt" variant="wheel" hour12 />

<!-- Clock -->
<TimePicker name="start" variant="clock" value="09:30" />

Demos

30-minute booking slots

<Label for="tp-slot">Drop-off</Label>
<TimePicker id="tp-slot" name="slot" step={30} min="09:00" max="17:00"/>

12-hour labels

<Label for="tp-12">Reminder</Label>
<TimePicker
  id="tp-12"
  name="reminder"
  step={15}
  hour12
  placeholder="Pick a reminder time"
/>

Native time input

<Label for="tp-native">Starts at</Label>
<TimePicker id="tp-native" name="starts" variant="input" step={15} value="09:30"/>

Wheel (scroll-drum) picker

<!-- 24-hour -->
<TimePicker variant="wheel" name="appt" value="14:30" />

<!-- 12-hour with AM/PM column -->
<TimePicker variant="wheel" name="appt" hour12 value="02:45" />

Circular clock picker

:
:
<!-- 24-hour -->
<TimePicker variant="clock" name="meeting" value="09:30" />

<!-- 12-hour with AM/PM toggle -->
<TimePicker variant="clock" name="meeting" hour12 value="09:30" />

API

Props

PropTypeDefaultDescription
variant"select" | "input" | "wheel" | "clock""select"Interaction pattern.
namestring—Form field name.
valuestring—Initial value (`HH:mm`).
minstring—Earliest time (`HH:mm`) — select/wheel.
maxstring—Latest time (`HH:mm`) — select/wheel.
stepnumber1Slot interval in minutes (select/wheel).
hour12booleanfalse12-hour display with AM/PM (wheel/clock/select).
localestring"en-US"Locale for slot labels (select).
placeholderstring"Select a time"Empty option label (select variant).
size"sm" | "md" | "lg""md"Control size (select/input/wheel).
invalidbooleanfalseSets `aria-invalid` and the error border.
requiredbooleanfalseRequired field.
disabledbooleanfalseDisabled field.
ariaLabelstring—Accessible name when there is no visible label.
classstring—Merged via cn(); Tailwind classes welcome.
idstring—Control id (use it in `<Label for>`).

Accessibility

Implemented accessibility features — semantics, ARIA wiring, and keyboard behavior that ship with the component.

  • Wheel and clock variants include a role='region' with aria-label
  • Wheel has an aria-live region that announces the current time after each change
  • Clock display buttons use aria-pressed to convey active mode (hour vs minute)
  • select / input variants use native elements — no custom widget to mis-key
  • aria-invalid accompanies the invalid border on all variants
  • Give the control a <Label for> or ariaLabel

FAQ

How do I read the selected time from the wheel or clock?

Listen for `change` (or `input`) on the hidden `<input type="hidden">` inside the component, or read the form value by `name` on submit. The value is always `HH:mm`.

Does the wheel support touch?

Yes — the drum uses the Pointer Events API which covers mouse, touch, and stylus. `touch-action: none` is set on the drum so the page doesn't scroll while you spin it.

How do I submit a timezone?

Send the local wall-clock `HH:mm` plus a separate timezone field (or an ISO datetime) — a bare time has no zone, so the server must be told which one it is.

Can I combine it with DatePicker?

Yes — put a DatePicker and a TimePicker side by side with `name="date"` and `name="time"`, then combine them server-side.

Changelog

Version history mentioning TimePicker.

v0.1.0 — 2026-11-11
added
  • Forms (18): Autocomplete, Combobox, Label, Field, Input, InputGroup, Textarea, Select, Checkbox, Radio, Switch, Toggle, ToggleGroup, RadioGroup, Rating, Slider, DatePicker, TimePicker.