Overview
This guide will help you create your first wheel picker component. We’ll cover both controlled and uncontrolled patterns, and show you how to build common use cases like time pickers and selection menus.
Make sure you’ve completed the installation before proceeding.
Basic Usage
Simple Controlled Picker
The most common pattern is a controlled component where you manage the selected value in state:
import { useState } from "react" ;
import {
WheelPicker ,
WheelPickerWrapper ,
type WheelPickerOption ,
} from "@ncdai/react-wheel-picker" ;
const frameworks : WheelPickerOption [] = [
{ label: "Next.js" , value: "nextjs" },
{ label: "Vite" , value: "vite" },
{ label: "Remix" , value: "remix" },
{ label: "Astro" , value: "astro" },
{ label: "Gatsby" , value: "gatsby" },
];
export function FrameworkPicker () {
const [ value , setValue ] = useState ( "nextjs" );
return (
< div >
< p > Selected framework: { value } </ p >
< WheelPickerWrapper >
< WheelPicker
options = { frameworks }
value = { value }
onValueChange = { setValue }
/>
</ WheelPickerWrapper >
</ div >
);
}
Uncontrolled Picker
For simpler use cases, you can use an uncontrolled component with defaultValue:
import {
WheelPicker ,
WheelPickerWrapper ,
type WheelPickerOption ,
} from "@ncdai/react-wheel-picker" ;
const sizes : WheelPickerOption [] = [
{ label: "Small" , value: "sm" },
{ label: "Medium" , value: "md" },
{ label: "Large" , value: "lg" },
{ label: "Extra Large" , value: "xl" },
];
export function SizePicker () {
const handleChange = ( value : string ) => {
console . log ( "Selected size:" , value );
};
return (
< WheelPickerWrapper >
< WheelPicker
options = { sizes }
defaultValue = "md"
onValueChange = { handleChange }
/>
</ WheelPickerWrapper >
);
}
Component Structure
WheelPickerWrapper
The wrapper component provides the container structure: < WheelPickerWrapper className = "w-56 rounded-md border" >
{ /* Place one or more WheelPicker components here */ }
</ WheelPickerWrapper >
WheelPicker
The picker component renders a single scrollable wheel: < WheelPicker
options = { options }
value = { value }
onValueChange = { setValue }
/>
Options Array
Define your options with labels and values: const options : WheelPickerOption [] = [
{ label: "Display Text" , value: "internal-value" },
];
Common Patterns
Multiple Wheels (Time Picker)
Combine multiple wheel pickers for complex selections:
import { useState } from "react" ;
import {
WheelPicker ,
WheelPickerWrapper ,
type WheelPickerOption ,
} from "@ncdai/react-wheel-picker" ;
// Generate hour options (1-12)
const hours : WheelPickerOption < number >[] = Array . from ({ length: 12 }, ( _ , i ) => ({
label: String ( i + 1 ). padStart ( 2 , "0" ),
value: i + 1 ,
}));
// Generate minute options (0-59)
const minutes : WheelPickerOption < number >[] = Array . from ({ length: 60 }, ( _ , i ) => ({
label: String ( i ). padStart ( 2 , "0" ),
value: i ,
}));
// AM/PM options
const periods : WheelPickerOption [] = [
{ label: "AM" , value: "am" },
{ label: "PM" , value: "pm" },
];
export function TimePicker () {
const [ hour , setHour ] = useState ( 12 );
const [ minute , setMinute ] = useState ( 0 );
const [ period , setPeriod ] = useState ( "am" );
const formattedTime = ` ${ String ( hour ). padStart ( 2 , "0" ) } : ${ String ( minute ). padStart ( 2 , "0" ) } ${ period . toUpperCase () } ` ;
return (
< div >
< p > Selected time: { formattedTime } </ p >
< WheelPickerWrapper >
< WheelPicker
options = { hours }
value = { hour }
onValueChange = { setHour }
/>
< WheelPicker
options = { minutes }
value = { minute }
onValueChange = { setMinute }
infinite
/>
< WheelPicker
options = { periods }
value = { period }
onValueChange = { setPeriod }
/>
</ WheelPickerWrapper >
</ div >
);
}
Enable infinite loop for options that should wrap around:
import { useState } from "react" ;
import {
WheelPicker ,
WheelPickerWrapper ,
type WheelPickerOption ,
} from "@ncdai/react-wheel-picker" ;
const numbers : WheelPickerOption < number >[] = Array . from ({ length: 10 }, ( _ , i ) => ({
label: String ( i ),
value: i ,
}));
export function InfiniteNumberPicker () {
const [ value , setValue ] = useState ( 0 );
return (
< WheelPickerWrapper >
< WheelPicker
options = { numbers }
value = { value }
onValueChange = { setValue }
infinite
/>
</ WheelPickerWrapper >
);
}
The infinite prop enables seamless wrapping, perfect for circular data like time, dates, or rotating selections.
Disabled Options
Mark specific options as disabled:
import { useState } from "react" ;
import {
WheelPicker ,
WheelPickerWrapper ,
type WheelPickerOption ,
} from "@ncdai/react-wheel-picker" ;
const dates : WheelPickerOption < number >[] = [
{ label: "Jan 1" , value: 1 },
{ label: "Jan 2" , value: 2 , disabled: true },
{ label: "Jan 3" , value: 3 },
{ label: "Jan 4" , value: 4 , disabled: true },
{ label: "Jan 5" , value: 5 },
];
export function DatePicker () {
const [ date , setDate ] = useState ( 1 );
return (
< WheelPickerWrapper >
< WheelPicker
options = { dates }
value = { date }
onValueChange = { setDate }
/>
</ WheelPickerWrapper >
);
}
Disabled options are automatically skipped during keyboard navigation and cannot be selected by clicking.
TypeScript with Generic Types
Use TypeScript generics for type-safe value handling:
import { useState } from "react" ;
import {
WheelPicker ,
WheelPickerWrapper ,
type WheelPickerOption ,
} from "@ncdai/react-wheel-picker" ;
// Number values
const quantities : WheelPickerOption < number >[] = [
{ label: "1 item" , value: 1 },
{ label: "2 items" , value: 2 },
{ label: "5 items" , value: 5 },
{ label: "10 items" , value: 10 },
];
export function QuantityPicker () {
const [ quantity , setQuantity ] = useState < number >( 1 );
return (
< WheelPickerWrapper >
< WheelPicker < number >
options = { quantities }
value = { quantity }
onValueChange = { ( value : number ) => {
// value is typed as number
setQuantity ( value );
} }
/>
</ WheelPickerWrapper >
);
}
Styling
With Tailwind CSS
Use the classNames prop to apply Tailwind classes:
< WheelPickerWrapper className = "w-56 rounded-md border border-zinc-200 bg-white dark:border-zinc-800 dark:bg-zinc-950" >
< WheelPicker
options = { options }
value = { value }
onValueChange = { setValue }
classNames = { {
optionItem: "text-zinc-400 dark:text-zinc-500" ,
highlightWrapper:
"bg-zinc-100 text-zinc-950 dark:bg-zinc-900 dark:text-zinc-50 data-rwp-focused:ring-2 data-rwp-focused:ring-zinc-300" ,
highlightItem: "font-medium" ,
} }
/>
</ WheelPickerWrapper >
With CSS
Target data attributes for CSS-based styling:
[ data-rwp-wrapper ] {
width : 14 rem ;
border-radius : 0.375 rem ;
border : 1 px solid #e4e4e7 ;
}
[ data-rwp-option ] {
color : #a1a1aa ;
}
[ data-rwp-highlight-wrapper ] {
background-color : #f4f4f5 ;
color : #09090b ;
}
Keyboard Navigation
React Wheel Picker includes comprehensive keyboard support:
Navigate through options one at a time
Move focus between multiple pickers in the same wrapper
Jump to the first or last option (non-infinite mode)
Type characters to quickly jump to matching options
Next Steps
API Reference Explore all available props and configuration options
Advanced Examples See complex implementations and real-world use cases
Customization Learn about styling with classNames and data attributes
TypeScript Dive deep into type definitions and generics
You’re now ready to build amazing wheel picker interfaces!