Touch-style 3D drum picker with any number of columns: rows tilt by their distance from the centre, and drags or flicks glide with momentum before snapping to a value.
pickerwheeltime pickeriosselect3dmomentumsnapdrum
Installation
Pro installs use your private registry token. Add the @geturui-pro registry once — setup guide. The command works after you get Pro.
$npx shadcn@latest add @geturui-pro/wheel-picker
Usage
usage.tsx
1"use client";
2import * as React from "react";
3import { WheelPicker, type WheelColumn } from "@/components/ui/wheel-picker";
4
5const pad = (n: number) => String(n).padStart(2, "0");
6const columns: WheelColumn[] = [
7 { key: "hour", label: "Hour", align: "right", options: Array.from({ length: 12 }, (_, i) => ({ value: String(i + 1), label: String(i + 1) })) },
8 { key: "minute", label: "Minute", options: Array.from({ length: 60 }, (_, i) => ({ value: pad(i), label: pad(i) })) },
9 { key: "period", label: "AM or PM", align: "left", options: [{ value: "AM", label: "AM" }, { value: "PM", label: "PM" }] },
10];
11
12export function AlarmTime() {
13 const [time, setTime] = React.useState({ hour: "7", minute: "30", period: "AM" });
14 return <WheelPicker aria-label="Alarm time" columns={columns} value={time} onValueChange={setTime} />;
15}
Props
| Prop | Type | Default | Description |
|---|---|---|---|
columns* | { key: string; label: string; options: { value: string; label: string }[]; width?: number; align?: "left" | "center" | "right" }[] | — | One wheel per column. label names the wheel for assistive tech. |
value | Record<string, string> | — | Controlled selection keyed by column key. |
defaultValue | Record<string, string> | first option of each column | Selection on mount when uncontrolled. |
onValueChange | (value: Record<string, string>) => void | — | Called as soon as a wheel picks its landing row. |
itemHeight | number | 36 | Row height in px; the wheel radius and height derive from it. |
aria-label | string | — | Names the group of wheels. |
className | string | — | Classes for the picker surface. |
Accessibility
- Each wheel is a focusable role="spinbutton" with aria-valuenow and aria-valuetext set to the visible label.
- Up and Down step one row, Page Up and Page Down jump five, Home and End go to the ends.
- Mouse wheel and trackpad scroll the wheel without scrolling the page; tapping a row selects it.
- With reduced motion the wheel snaps with a short tween instead of a momentum spring.