iOS-like wheel picker for React with smooth inertia scrolling and infinite loop support.
If you're using shadcn/ui, please refer to the guide: https://chanhdai.com/blog/react-wheel-picker
pnpm add @ncdai/react-wheel-picker
The wheel picker consists of two main components:
The wrapper component that contains one or more wheel pickers. It provides the container structure and handles the layout of multiple wheels.
<WheelPickerWrapper>
<WheelPicker />
<WheelPicker />
<WheelPicker />
</WheelPickerWrapper>
The core component that renders a single wheel of options. Each wheel picker consists of:
<WheelPicker
options={[
{ label: "React", value: "react" },
{ label: "Vue", value: "vue" },
{ label: "Angular", value: "angular" },
]}
/>
Add the core CSS to your app's entry point (e.g., src/app/layout.tsx
, src/main.tsx
, or src/index.tsx
):
import "@ncdai/react-wheel-picker/dist/style.css";
This CSS includes only basic layout. Use classNames to customize visuals (see below).
import {
WheelPicker,
WheelPickerWrapper,
type WheelPickerOption,
type WheelPickerClassNames,
} from "@ncdai/react-wheel-picker";
const options: WheelPickerOption[] = [
{
label: "React",
value: "react",
},
{
label: "Vue",
value: "vue",
},
{
label: "Angular",
value: "angular",
},
{
label: "Svelte",
value: "svelte",
},
];
const classNames: WheelPickerClassNames = {
optionItem: "text-zinc-400",
highlightWrapper: "bg-zinc-100 text-zinc-950",
};
export function WheelPickerDemo() {
return (
<WheelPickerWrapper className="max-w-56 rounded-md border border-zinc-200 bg-white shadow-xs">
<WheelPicker options={options} classNames={classNames} />
</WheelPickerWrapper>
);
}
Props for the WheelPicker
component:
Prop | Type | Default | Description |
---|---|---|---|
options | WheelPickerOption[] | (required) | Array of options to display in the wheel |
value | string | - | Current value of the picker (controlled mode) |
defaultValue | string | - | Default value of the picker (uncontrolled mode) |
onValueChange | (value: string) => void | - | Callback fired when the selected value changes |
infinite | boolean | false | Enable infinite scrolling |
visibleCount | number | 20 | Number of options visible on the wheel (must be multiple of 4) |
dragSensitivity | number | 3 | Sensitivity of the drag interaction (higher = more sensitive) |
classNames | WheelPickerClassNames | - | Custom class names for styling |
Props for the WheelPickerWrapper
component:
Prop | Type | Default | Description |
---|---|---|---|
className | string | - | CSS class name for wrapper |
children | React.ReactNode | (required) | WheelPicker components |
type WheelPickerOption = {
/** Value that will be returned when this option is selected */
value: string;
/** Text label displayed for this option */
label: string;
};
type WheelPickerClassNames = {
/** Class name for individual option items */
optionItem?: string;
/** Class name for the wrapper of the highlighted area */
highlightWrapper?: string;
/** Class name for the highlighted item */
highlightItem?: string;
};