React Wheel Picker

repository·main·Indexed 20 days ago

https://github.com/ncdai/react-wheel-picker

An iOS-style wheel picker component for React featuring smooth inertia scrolling, infinite loop support, and an unstyled core for easy customization. It includes full keyboard navigation, type-ahead search, and supports both controlled and uncontrolled modes. The library provides WheelPicker and WheelPickerWrapper components, as well as a WheelPickerGroupProvider and useWheelPickerGroup hook for coordinating multiple pickers.

Tokens
4.1K
Snippets
13
Records
20
Agent score
72%

What's inside react-wheel-picker

  1. Overview of React Wheel Picker

    main

    React Wheel Picker is an iOS-like wheel picker component designed for React applications. It provides a smooth, high-quality selection interface with several key features:

    • Natural Scrolling: Supports touch scrolling with smooth inertia, as well as mouse drag and scroll for desktop users.
    • Infinite Loop: Supports infinite loop scrolling for continuous selection.
    • Unstyled Core: The core logic is unstyled, allowing for complete CSS/style customization to match your application's design.
    • Accessibility: Includes full keyboard navigation and type-ahead search capabilities.
  2. How WheelPicker components work together

    main

    The wheel picker is composed of two main components that work in a parent-child relationship:

    1. WheelPickerWrapper: The container component. It manages the layout for one or more wheels and provides the overall structure.
    2. WheelPicker: The core component that renders an individual wheel. Each WheelPicker includes a 3D perspective container, a scrollable list, a highlight area for the selected option, and a mask for the fade effect.

    To create a multi-column picker (like a date picker), wrap multiple WheelPicker components inside a single WheelPickerWrapper.

    <WheelPickerWrapper>
      <WheelPicker />
      <WheelPicker />
      <WheelPicker />
    </WheelPickerWrapper>
  3. Use WheelPicker with Primitives

    main

    When using the primitives package, follow these steps:

    1. Import Styles: Add the core CSS to your application's entry point (e.g., src/app/layout.tsx or src/main.tsx) to ensure basic layout works:

      import "@ncdai/react-wheel-picker/style.css";
    2. Implement Component: Import WheelPicker, WheelPickerWrapper, and WheelPickerOption from @ncdai/react-wheel-picker and pass your options and state handlers.

    import { WheelPicker, WheelPickerWrapper, type WheelPickerOption } from "@ncdai/react-wheel-picker";
    
    const options: WheelPickerOption[] = [
      { label: "Next.js", value: "nextjs" },
      { label: "Vite", value: "vite" },
    ];
    
    export function WheelPickerDemo() {
      const [value, setValue] = useState("nextjs");
    
      return (
        <WheelPickerWrapper>
          <WheelPicker options={options} value={value} onValueChange={setValue} />
        </WheelPickerWrapper>
      );
    }
  4. Run the development server for the web application

    main

    To start the local development environment for the web application, run the development command using your preferred package manager. Once started, the application will be available at http://localhost:3000.

    npm run dev
    # or
    yarn dev
    # or
    pnpm dev
    # or
    bun dev
  5. Keyboard Navigation and Type-ahead Search

    main

    The WheelPicker supports full keyboard accessibility:

    • Vertical Navigation: ArrowUp and ArrowDown scroll the wheel to the next/previous enabled item.
    • Picker Switching: In a WheelPickerWrapper group, ArrowLeft and ArrowRight move focus between different pickers.
    • Jump to Bounds: Home jumps to the first enabled item; End jumps to the last enabled item (only in non-infinite mode).
    • Type-ahead Search: Typing a character will search for the nearest option whose label or textValue matches the character and scroll to it.
    • Focus: The component is focusable via Tab and manages its own tabIndex within a group.
  6. WheelPicker API Reference

    main

    The WheelPicker component is the primary interactive element. It supports both controlled and uncontrolled modes.

    Props

    PropTypeDefaultDescription
    optionsWheelPickerOption<T>[](required)Array of options to display
    valueT-Current value (controlled mode)
    defaultValueT-Initial value (uncontrolled mode)
    onValueChange(value: T) => void-Callback when selection changes
    infinitebooleanfalseEnable infinite scrolling
    visibleCountnumber20Number of visible options (must be multiple of 4)
    dragSensitivitynumber3Drag interaction sensitivity
    scrollSensitivitynumber5Scroll interaction sensitivity
    optionItemHeightnumber30Height in pixels of each item
    classNamesWheelPickerClassNames-Custom class names for styling
  7. Style the WheelPicker using Data Attributes

    main

    You can target specific elements of the wheel picker using CSS data attributes. This is useful for custom themes.

    Available Data Attributes

    AttributeElementDescription
    [data-rwp-wrapper]WrapperApplied to WheelPickerWrapper
    [data-rwp]PickerApplied to WheelPicker root
    [data-rwp-options]Options containerApplied to the options list container
    [data-rwp-option]Option itemApplied to each option item
    [data-rwp-highlight-wrapper]Highlight wrapperApplied to the highlight area wrapper
    [data-rwp-highlight-list]Highlight listApplied to the highlight list container
    [data-rwp-highlight-item]Highlight itemApplied to the highlighted option item
    [data-rwp-focused]Highlight wrapperPresent on [data-rwp-highlight-wrapper] when focused
    [data-disabled]Option/HighlightPresent on items when disabled
  8. Use WheelPickerWrapper for multiple pickers

    main

    To manage multiple WheelPicker components as a single group (e.g., for coordinated keyboard navigation where Arrow keys move focus between pickers), wrap them in a WheelPickerWrapper. This provides the necessary context for the pickers to interact with each other.

    import { WheelPicker, WheelPickerWrapper } from '@ncdai/react-wheel-picker';
    
    function MultiPicker() {
      return (
        <WheelPickerWrapper>
          <WheelPicker options={hours} />
          <WheelPicker options={minutes} />
          <WheelPicker options={seconds} />
        </WheelPickerWrapper>
      );
    }
  9. Use the useWheelPickerGroup hook to coordinate pickers

    main

    The useWheelPickerGroup hook allows you to access and manipulate the state of a group of wheel pickers. It returns a WheelPickerGroupContextValue object containing the following properties:

    • activeIndex: The index of the currently active picker.
    • setActiveIndex: A function to set the active picker index ((index: number) => void).
    • register: A function to register a picker's DOM element and retrieve its index. It takes an existingIndex (or null for new pickers) and a ref to the HTMLDivElement. Returns the assigned number index.
    • getPickerRef: A function to retrieve the HTMLDivElement for a specific picker index ((index: number) => HTMLDivElement | null).
    • getPickerIndices: A function that returns an array of all registered picker indices (() => number[]).
    import { useWheelPickerGroup } from '@ncdai/react-wheel-picker';
    import { useRef, useEffect } from 'react';
    
    function MyPicker() {
      const { register, activeIndex, setActiveIndex } = useWheelPickerGroup();
      const pickerRef = useRef<HTMLDivElement>(null);
      
      // Register the picker on mount
      const index = register(null, pickerRef.current!);
    
      return (
        <div ref={pickerRef}>
          {/* Picker implementation */}
        </div>
      );
    }
  10. Use the WheelPicker component

    main

    The WheelPicker is the primary component for creating a scrollable wheel selection interface. It supports both controlled and uncontrolled modes, infinite scrolling, and keyboard navigation (including type-ahead search).

    Basic Usage

    import { WheelPicker } from '@ncdai/react-wheel-picker';
    
    const options = [
      { label: 'Option 1', value: '1' },
      { label: 'Option 2', value: '2' },
      { label: 'Option 3', value: '3' },
    ];
    
    function MyComponent() {
      return (
        <WheelPicker
          options={options}
          onValueChange={(val) => console.log('Selected:', val)}
        />
      );
    }
  11. Configure WheelPicker props

    main

    The WheelPicker component accepts several props to customize its behavior and appearance:

    PropTypeDefaultDescription
    optionsWheelPickerOption<T>[]RequiredArray of items to display in the wheel.
    valueT-The currently selected value (for controlled mode).
    defaultValueT-The initial selected value (for uncontrolled mode).
    onValueChange(value: T) => void-Callback triggered when the selection changes.
    infinitebooleanfalseIf true, the wheel wraps around from the last item to the first.
    visibleCountnumber20The number of items used to calculate the wheel's geometry.
    dragSensitivitynumber3Multiplier for drag-based scrolling.
    scrollSensitivitynumber5Multiplier for wheel-based scrolling.
    optionItemHeightnumber30The height of a single item in pixels.
    classNamesWheelPickerClassNames-Object containing custom CSS class names for various sub-elements.