Skip to content
Native Animation
Wheel Picker animation preview

react native wheel picker

Wheel Picker

A reusable horizontal wheel picker that gives uneven labels a precise center, physical momentum, and an optional 3D curve.

$9 for this animation

Add to your project

Copy the component and its assets into your app with the Native Animation CLI, or paste the agent prompt into Claude Code, Codex or Cursor once the MCP server is connected.

npx nativeanimation add wheel-picker

About this animation

A React Native wheel picker should center short and long labels with equal precision instead of forcing every option into a fixed-width cell. This horizontal picker measures each label, then resolves taps, drags, momentum, and programmatic changes against its true center. Use it for genres, years, sizes, filters, or any compact choice set that benefits from a tactile browsing rhythm. One continuous Reanimated offset drives translation, scale, opacity, color, vertical curvature, and optional 3D rotation, while Gesture Handler preserves release velocity before the nearest option settles. The component supports controlled and uncontrolled values, custom label rendering, adjustable curve strength, colors, typography, change callbacks, and imperative next, previous, and select controls.

When to use it

  • Choose genres, years, sizes, or filter values.
  • Center labels with different measured widths.
  • Add momentum and an optional 3D curve to selection.
  • Control a picker through gestures, taps, or a ref.

A reusable horizontal wheel picker that gives uneven labels a precise center, physical momentum, and an optional 3D curve.

Why this one

Most horizontal pickers assume every option has the same width or hide the behavior inside a single screen. This component measures every label, supports controlled and uncontrolled state, and resolves momentum against the real center of each option. Its optional perspective curve, touch targets, imperative controls, and adjustable screen-reader actions make it useful beyond the included movie-filter demo.

How it works

  1. Every option reports its real layout center, so labels such as “Crime” and “Science Fiction” align without a fixed cell width.
  2. One continuous pixel offset drives track translation, scale, opacity, color, vertical curvature, and Y-axis rotation.
  3. A pan directly updates that offset with elastic edge resistance. On release, withDecay preserves momentum before a spring settles on the nearest measured center.
  4. Tapping an option, calling the forwarded ref, or using an accessibility increment/decrement action follows the same selection path.
  5. The centered item emits a short violet glow pulse while reduced-motion mode replaces physical movement with a brief transition.

Install

npx expo install expo-linear-gradient react-native-gesture-handler react-native-reanimated react-native-worklets

Usage

import WheelPicker from './WheelPicker';

export function GenreFilter() {
  return (
    <WheelPicker
      options={['Comedy', 'Drama', 'Science Fiction']}
      defaultValue="Comedy"
      onChange={(genre) => applyGenre(genre)}
    />
  );
}

Use controlled state and personality knobs when the picker belongs to a larger form:

const [year, setYear] = useState(2019);

<WheelPicker
  accessibilityLabel="Release year"
  activeColor="#15151C"
  curve={0.8}
  fontFamily="YourSansMedium"
  fontSize={20}
  inactiveColor="#9898A6"
  onChange={setYear}
  options={[2018, 2019, 2020, 2021]}
  renderLabel={(value) => String(value)}
  value={year}
/>;

The forwarded ref exposes next(), previous(), and select(value).

Props

PropTypeDefaultDescription
optionsT[]RequiredValues displayed from first to last.
valueT—Controlled selected value.
defaultValueTFirst optionInitial uncontrolled value.
onChange(value: T) => void—Called whenever the centered value changes.
renderLabel(value: T) => stringString(value)Produces the visible and accessible label.
curvenumber0.6Perspective strength from 0 to 1.
fontFamilystringSystem fontOption-label font family.
activeColorstring'#111111'Centered-option color.
inactiveColorstring'#A3A3A3'Side-option color.
fontSizenumber18Base label size in points.
accessibilityLabelstring'Option picker'Label for the adjustable control.
styleStyleProp<ViewStyle>—Outer-container style.
testIDstring—Test identifier for the outer container.

Compatibility

  • Expo SDK 57
  • React Native 0.86
  • Reanimated 4.5 and Worklets 0.10
  • iOS: supported, not yet verified on a device
  • Android: supported, not yet verified on a device
  • Web: supported, verified by the project export and bundle gate
  • Works in Expo Go because its native dependencies are included in the SDK

Accessibility

The gesture surface uses the adjustable role, announces the selected label and position, and supports increment and decrement actions. Every option is also a labeled button, so tapping is an alternative to dragging. Reduced-motion mode removes perspective movement and decay, then settles with a short 180 ms transition.

FAQ

Does this React Native wheel picker work in Expo Go?
Yes. Expo Linear Gradient, Gesture Handler, Reanimated, and Worklets are included with Expo SDK 57. Web is verified; iOS and Android are supported with device verification still pending.
Can the wheel picker handle labels with different widths?
Yes. It measures the real center of every option, so labels such as short years and longer category names settle precisely without fixed-width cells.
How can people use the picker without dragging?
Every option is a labeled button, the adjustable control supports increment and decrement actions, and the ref exposes next, previous, and select. Reduce Motion removes perspective and decay.