Wheel Time Picker
An iOS-style 3D wheel for picking a time: momentum scrolling, snapping, and a perspective arc.
This is a WebberUI Pro component
The install command below needs a licence to run; without one it returns 401.
An iOS-style two-column hour/minute 3D wheel: the numbers are laid out along an arc with rotateX (the further away, the more tilted and faded), it supports momentum gliding from both dragging and the mouse wheel, and on release a spring snaps it to the nearest tick. The selected row has a highlight frame, and once focused it can also be nudged with the up/down arrow keys.
Bring this into your project
Run this command in your project folder. The CLI adds the source and dependencies; then follow the usage example below.
npx webberui@latest add "https://webberui.com/r/wheel-time-picker.en.json?t=<install token>"Playground
Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.
<WheelTimePicker/>
The complete example includes the preview layout and data. Install the component first, then paste this file into your project.
Installation
npx webberui@latest add "https://webberui.com/r/wheel-time-picker.en.json?t=<install token>"Or, once registries are configured in components.json, install it as @webberui/wheel-time-picker.
Usage
import { WheelTimePicker } from "@/components/ui/wheel-time-picker";
<WheelTimePicker
defaultValue="09:30"
minuteStep={5}
onChange={(time) => console.log(time)}
/>Props
| Prop | Type | Default | Description |
|---|---|---|---|
value | string | — | Controlled time value ("HH:mm"); the wheel turns smoothly to the matching position when it changes externally |
defaultValue | string | "09:30" | Initial value in uncontrolled mode ("HH:mm") |
onChange | (value: string) => void | — | Returns the new time string once the wheel snaps into place ("HH:mm") |
minuteStep | number | 5 | Interval between minute ticks (1–30); the default produces 00, 05…55 |
itemHeight | number | 40 | Height of a single row (px), which also determines the radius of the 3D arc |
labels | { hour: string; minute: string } | { hour: "Time", minute: "Points" } | Accessible labels for the hour and minute columns |
className | string | — | Forwarded to the outer container |
Accessibility
- Each column is
role="spinbutton"witharia-valuemin,aria-valuemax, andaria-valuetext, and once focused it can be nudged tick by tick with the up/down arrow keys - The individual numbers on the arc are hidden from assistive technology (
aria-hidden) to avoid duplicate reading; the actual value is announced througharia-valuetext - When the user has "reduce motion" enabled at the system level, the momentum and spring animations are disabled and it snaps directly into position
- Mouse dragging, touch, and the scroll wheel are all supported as pointer input, and the default row height of 40px gives a large enough touch target