React Wheel Picker
iOS-like wheel picker for React with smooth inertia scrolling and infinite loop support.
Loading...
import type { WheelPickerOption } from "@/components/ncdai/wheel-picker";
import { WheelPicker, WheelPickerWrapper } from "@/components/ncdai/wheel-picker";
const createArray = (length: number, add = 0): WheelPickerOption<number>[] =>
Array.from({ length }, (_, i) => {
const value = i + add;
return {
label: value.toString().padStart(2, "0"),
value: value,
};
});
const hourOptions = createArray(12, 1);
const minuteOptions = createArray(60);
const meridiemOptions: WheelPickerOption[] = [
{ label: "AM", value: "AM" },
{ label: "PM", value: "PM" },
];
export function WheelPickerDemo() {
return (
<div className="w-56">
<WheelPickerWrapper>
<WheelPicker options={hourOptions} defaultValue={9} infinite />
<WheelPicker options={minuteOptions} defaultValue={41} infinite />
<WheelPicker options={meridiemOptions} defaultValue="AM" />
</WheelPickerWrapper>
</div>
);
}About
The Wheel Picker component is built on top of React Wheel Picker.
- 📱 Natural touch scrolling with smooth inertia effect
- 🖱️ Mouse drag and scroll support for desktop
- 🔄 Infinite loop scrolling
- 🎨 Unstyled components for complete style customization
- ⚡️ Easy installation via shadcn CLI
Installation
pnpm dlx shadcn add @ncdai/wheel-picker
Usage
import {
WheelPicker,
WheelPickerWrapper,
type WheelPickerOption,
} from "@/components/ncdai/wheel-picker";const options: WheelPickerOption[] = [
{
label: "React",
value: "react",
},
{
label: "Vue",
value: "vue",
},
{
label: "Angular",
value: "angular",
},
{
label: "Svelte",
value: "svelte",
},
];
export function WheelPickerDemo() {
const [value, setValue] = useState("react");
return (
<WheelPickerWrapper>
<WheelPicker options={options} value={value} onValueChange={setValue} />
</WheelPickerWrapper>
);
}See the React Wheel Picker documentation for more information.
Examples
Multiple Pickers, Infinite Loop
Loading...
import type { WheelPickerOption } from "@/components/ncdai/wheel-picker";
import { WheelPicker, WheelPickerWrapper } from "@/components/ncdai/wheel-picker";
const createArray = (length: number, add = 0): WheelPickerOption<number>[] =>
Array.from({ length }, (_, i) => {
const value = i + add;
return {
label: value.toString().padStart(2, "0"),
value: value,
};
});
const hourOptions = createArray(12, 1);
const minuteOptions = createArray(60);
const meridiemOptions: WheelPickerOption[] = [
{ label: "AM", value: "AM" },
{ label: "PM", value: "PM" },
];
export function WheelPickerDemo() {
return (
<div className="w-56">
<WheelPickerWrapper>
<WheelPicker options={hourOptions} defaultValue={9} infinite />
<WheelPicker options={minuteOptions} defaultValue={41} infinite />
<WheelPicker options={meridiemOptions} defaultValue="AM" />
</WheelPickerWrapper>
</div>
);
}React Hook Form
Loading...
"use client";
import { zodResolver } from "@hookform/resolvers/zod";
import type { SubmitHandler } from "react-hook-form";
import { useForm } from "react-hook-form";
import { toast } from "sonner";
import { z } from "zod";
import { Button } from "@/components/ui/button";
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form";
import type { WheelPickerOption } from "@/components/ncdai/wheel-picker";
import { WheelPicker, WheelPickerWrapper } from "@/components/ncdai/wheel-picker";
const formSchema = z.object({
framework: z.string(),
});
type FormSchema = z.infer<typeof formSchema>;
const options: WheelPickerOption[] = [
{
label: "Vite",
value: "vite",
},
{
label: "Laravel",
value: "laravel",
},
{
label: "React Router",
value: "react-router",
},
{
label: "Next.js",
value: "nextjs",
},
{
label: "Astro",
value: "astro",
},
{
label: "TanStack Start",
value: "tanstack-start",
},
{
label: "TanStack Router",
value: "tanstack-router",
},
{
label: "Gatsby",
value: "gatsby",
},
];
export function WheelPickerFormDemo() {
const form = useForm<FormSchema>({
resolver: zodResolver(formSchema),
defaultValues: {
framework: "nextjs",
},
});
const onSubmit: SubmitHandler<FormSchema> = (values) => {
toast("You submitted the following values:", {
description: (
<pre className="mt-2 w-80 rounded-lg bg-zinc-950 p-4">
<code className="text-white">{JSON.stringify(values, null, 2)}</code>
</pre>
),
});
};
return (
<Form {...form}>
<form
onSubmit={form.handleSubmit(onSubmit)}
className="w-56 max-w-full space-y-4"
>
<FormField
control={form.control}
name="framework"
render={({ field }) => (
<FormItem>
<FormLabel>Framework</FormLabel>
<FormControl>
<WheelPickerWrapper>
<WheelPicker
options={options}
value={field.value}
onValueChange={field.onChange}
/>
</WheelPickerWrapper>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<div className="flex justify-center">
<Button type="submit">Submit</Button>
</div>
</form>
</Form>
);
}