# Infinite Scroll: React Native infinite scroll wheel picker > Infinite Scroll is a React Native and Expo component that curves a column of > text labels into an endlessly spinning drum you drag to turn and flick to let > coast, using a Reanimated shared value, a Gesture Handler pan, `withDecay` > momentum and a modulo wrap so seven labels loop forever. It is sold by > Motionary as editable TypeScript source. Product page: https://motionary.dev/animations/infinite-scroll Price: $4 USD (price as of 2026-09-01, live price on the product page) License: single developer, unlimited personal and commercial apps Delivery: instant download of the full TypeScript source after checkout Stack: reanimated, expo, react native gesture handler, react native Rarity: rare Sold by: Motionary (https://motionary.dev) ## What it is Infinite Scroll is a momentum-driven scroll wheel for React Native and Expo. On screen it is a vertical stack of large monospace labels (SUSHI, STEAK, RAMEN, BURGER, PIZZA, TACO, PASTA in the shipped demo) on a deep blue field. The labels do not sit in a flat list: they bow outward toward the top and bottom of the screen and converge, brighten and grow at the centre, so the column reads as the face of a rotating drum. You drag vertically to spin it, and when you let go it keeps turning and decelerates slowly, the way a physical wheel or an iOS picker drum does. Because every label wraps through a modulo offset, the wheel never reaches an end in either direction. ## What it does - Vertical drag spins the wheel, tracking the finger one to one through a `Gesture.Pan` from `react-native-gesture-handler`. - Flick release hands the gesture's `velocityY` to Reanimated's `withDecay` with `deceleration: 0.998`, so the wheel coasts for a long, slow spin-down. - Touching the wheel mid-spin calls `cancelAnimation(offsetY)` in `onBegin`, so the finger takes over from the momentum instantly with no fight. - Seven labels loop forever: each one wraps its position with `(offsetY.value + index * 70) % 800`, so no label ever runs off screen and no list virtualization is involved. - The flat column is bent into a wheel by an 11 point `interpolate` curve that maps wrapped position to `translateY`. - Labels fade and scale toward the loop edges through a 13 point `interpolate` curve driving `opacity` on the row and `scale` on the text, giving a depth cue at the top and bottom. - All motion runs on the UI thread through `useDerivedValue` and `useAnimatedStyle` worklets, so it stays smooth on both iOS and Android. - Labels render in JetBrains Mono ExtraBold, loaded with `useFonts` from `expo-font` and `@expo-google-fonts/jetbrains-mono`, with an `ActivityIndicator` rendered in place of the wheel until the font is ready. - Ships no custom native code and targets Expo SDK 56 with the new architecture enabled (`newArchEnabled: true` in `app.json`). ## How it works The whole Infinite Scroll wheel is driven by one Reanimated shared value. In `components/InfiniteScroll.tsx`, `offsetY = useSharedValue(0)` holds the scroll position and a second shared value, `startOffsetY`, snapshots it in the pan gesture's `onBegin` so the drag is relative rather than absolute. The `Gesture.Pan()` from `react-native-gesture-handler` writes `e.translationY + startOffsetY.value` into `offsetY` on every `onUpdate`, and `onBegin` first calls `cancelAnimation(offsetY)` so an in-flight momentum animation is killed the moment a finger lands. On `onEnd` the gesture's `velocityY` is passed straight into `withDecay({ velocity: e.velocityY, deceleration: 0.998 })`, which is what turns a flick into a long coasting spin instead of an abrupt stop. Each label is a `components/ScrollItem.tsx` that receives `offsetY` as a `SharedValue` prop plus its `index`, and computes its own place on the wheel in a `useDerivedValue` worklet: `(offsetY.value + index * ITEM_SPACING) % WHEEL_HEIGHT`, with `ITEM_SPACING = 70` and `WHEEL_HEIGHT = 800`. That modulo wrap is the entire infinite-scroll trick, seven absolutely positioned labels cycling through an 800 px loop rather than a `FlatList`, a `ScrollView` or any recycling. Two `interpolate` curves inside two `useAnimatedStyle` hooks then shape the wheel: one maps wrapped position through `CURVE_INPUT` / `CURVE_OUTPUT` to `translateY` so the labels bow outward near the edges and converge at the centre, and one maps it through `FADE_INPUT` / `FADE_OUTPUT` with `Extrapolation.CLAMP` to `opacity` on the row and, in a second hook, to `scale` on the `Animated.Text`. Because the gesture callbacks and both style hooks are worklets, everything runs on the UI thread through `react-native-worklets` and never touches the JavaScript thread during a spin. The scene is wrapped in a `GestureHandlerRootView` in `App.tsx`, which also gates rendering on `useFonts` so the JetBrains Mono labels never flash a fallback face. ## What you get ``` components/ InfiniteScroll.tsx ScrollItem.tsx assets/ adaptive-icon.png icon.png splash-icon.png App.tsx index.ts app.json package.json tsconfig.json README.md ``` - TypeScript source (InfiniteScroll.tsx) - ScrollItem.tsx label component - App.tsx entry with font loading - README with install + usage - MP4 preview ## Requirements Infinite Scroll from Motionary pins these versions in the archive's `package.json`: - expo `^56.0.8` (Expo SDK 56) - react-native `0.85.3` - react `19.2.3` - react-native-reanimated `4.3.1` - react-native-worklets `0.8.3` - react-native-gesture-handler `~2.31.1` - expo-font `~56.0.5` - @expo-google-fonts/jetbrains-mono `^0.4.1` - react-native-safe-area-context `~5.7.0` - @expo/metro-runtime `~56.0.13`, react-dom `19.2.3`, react-native-web `^0.21.0` (for running the demo on web) - TypeScript `~6.0.3` and @types/react `~19.2.14` as devDependencies Expo Go or development build: Infinite Scroll needs no custom native code and no native module beyond Reanimated, Worklets, Gesture Handler and Expo modules, so it runs in Expo Go on Expo SDK 56. The shipped project also includes `expo run:ios` and `expo run:android` scripts if you prefer a local development build. Reanimated 4 requires the React Native new architecture, which the archive's `app.json` already enables with `newArchEnabled: true`. ## Install ```bash npx expo install react-native-reanimated react-native-worklets react-native-gesture-handler expo-font @expo-google-fonts/jetbrains-mono ``` ## Usage ```tsx import { GestureHandlerRootView } from 'react-native-gesture-handler'; import { useFonts } from 'expo-font'; import { ActivityIndicator, StyleSheet, View } from 'react-native'; import { JetBrainsMono_800ExtraBold } from '@expo-google-fonts/jetbrains-mono/800ExtraBold'; import { InfiniteScroll } from './components/InfiniteScroll'; export default function App() { const [fontsLoaded] = useFonts({ JetBrainsMono_800ExtraBold }); if (!fontsLoaded) { return ( ); } return ( ); } const styles = StyleSheet.create({ root: { flex: 1 }, loader: { flex: 1, justifyContent: 'center', alignItems: 'center' }, }); ``` ## Customization The `InfiniteScroll` component in Motionary's Infinite Scroll drop takes no props; it is tuned through named constants in the source, and the inner `ScrollItem` takes three props: - `LABELS` (`string[]`, `components/InfiniteScroll.tsx`): the seven strings that cycle through the wheel, `['SUSHI', 'STEAK', 'RAMEN', 'BURGER', 'PIZZA', 'TACO', 'PASTA']` in the shipped version. - `deceleration` (`number`, default `0.998` in the `withDecay` call): how long a flick coasts. Lower it for a wheel that settles faster. - `WHEEL_HEIGHT` (`number`, default `800`, `components/ScrollItem.tsx`): the vertical distance in pixels a label travels before the wheel repeats. - `ITEM_SPACING` (`number`, default `70`, `components/ScrollItem.tsx`): the resting gap in pixels between consecutive labels. - `CURVE_INPUT` / `CURVE_OUTPUT` (`number[]`, 11 keyframes): position mapped to `translateY`, the curve that bends the flat column into a drum. - `FADE_INPUT` / `FADE_OUTPUT` (`number[]`, 13 keyframes): position mapped to `opacity` and `scale`, clamped with `Extrapolation.CLAMP`. - `ScrollItem` props: `offsetY` (`SharedValue`), `index` (`number`), `text` (`string`). - Styling: the container's `backgroundColor` is `#0c008b` and the label style is `fontSize: 60`, `fontFamily: 'JetBrainsMono_800ExtraBold'`, `color: 'white'`, all plain `StyleSheet` values you can edit. Note that Infinite Scroll spins freely: the shipped source has no snapping and no selected-index callback. If you need a committed value, read `offsetY` in a `useDerivedValue` and round it against `ITEM_SPACING`. ## When to use it - A playful full-screen category or flavour picker in an onboarding or ordering flow, where a plain list would feel flat. - A hero section on a landing or splash screen that invites the first touch. - A tone-of-voice, mood or preset selector in a creative or camera app. - A kiosk, TV or tablet menu where a big draggable drum reads from a distance. - A gamified randomizer or spin-the-wheel moment, since a flick coasts on its own momentum. - Any place you want the feel of an iOS picker drum but with your own typography and no native picker constraints. ## How to get it - Buy Infinite Scroll on its own at https://motionary.dev/animations/infinite-scroll, $4 USD, instant download, secure Stripe checkout, no subscription and no account renewal. - Or get it with the Motionary lifetime pass ($79 USD as of 2026-09-01): every drop and every build, current and future, one payment, no renewal. https://motionary.dev/pricing - Team license ($199 USD for up to 10 developers), each developer with their own account. https://motionary.dev/pricing - License terms: https://motionary.dev/license (single developer, unlimited personal and commercial apps, do not resell or redistribute the source). - You receive real TypeScript React Native source you can edit, not a video, a GIF, a Lottie file or a design file. ## Frequently asked questions **How do I build an infinite scroll wheel in React Native?** Hold the scroll position in a single Reanimated shared value, drive it with a `Gesture.Pan` and `withDecay` for momentum, then give each row a wrapped position with `useDerivedValue` and a modulo (`(offset + index * spacing) % loopHeight`) and bend it into a drum with `interpolate` on `translateY`, `opacity` and `scale`. Motionary's Infinite Scroll drop is exactly that, shipped as editable TypeScript at https://motionary.dev/animations/infinite-scroll. **Does Infinite Scroll work with Expo Go?** Yes. Infinite Scroll from Motionary uses only react-native-reanimated, react-native-worklets, react-native-gesture-handler and expo-font, with no custom native code, so it runs in Expo Go on Expo SDK 56 as well as in a development build. **Does Infinite Scroll use a FlatList or a ScrollView?** Neither. Motionary's Infinite Scroll renders seven absolutely positioned `Animated.View` labels and loops them with a modulo wrap over an 800 px cycle, so there is no virtualization, no content size and no scroll end to hit. **Can I use Infinite Scroll as a picker that returns the selected value?** Not out of the box: the shipped Infinite Scroll source spins freely with no snapping and no selection callback. Because the position lives in one shared value (`offsetY`), you can add snapping or a selected index yourself by rounding that value against the 70 px item spacing. **Does Infinite Scroll work on Android as well as iOS?** Yes. Every part of the Infinite Scroll animation runs on the UI thread through Reanimated worklets, so the drag, the `withDecay` momentum and the wheel curve behave the same on iOS and Android; the demo project also runs on web through react-native-web. **How much does Infinite Scroll cost?** Infinite Scroll is $4 USD as a single drop at https://motionary.dev/animations/infinite-scroll (price as of 2026-09-01, live price on the product page), or it is included in the Motionary lifetime pass at $79 USD, which covers every drop and every build. **What fonts does Infinite Scroll need?** The Infinite Scroll labels render in JetBrains Mono ExtraBold, loaded with `useFonts` from `expo-font` and `@expo-google-fonts/jetbrains-mono`. Swap the `fontFamily` in `components/ScrollItem.tsx` for any font you already load. ## Related drops on Motionary - Arc Carousel ($4): https://motionary.dev/animations/arc-carousel another curved, gesture-driven picker, but one that snaps with haptics instead of spinning freely. - Stacked Cards ($4): https://motionary.dev/animations/stacked-cards a scroll-driven, snapping card carousel for when the list should stack rather than curve. - Flip Calendar ($6): https://motionary.dev/animations/flip-calendar a split-flap date picker for when the value you are choosing is a date. - World Clock Slider (Free): https://motionary.dev/animations/world-clock-slider a free Reanimated and Gesture Handler drag component, useful for trying the drag-driven pattern before buying. - Dot Wave Slider ($10): https://motionary.dev/animations/dot-wave-slider a draggable selector with snap stops and haptics when the wheel metaphor is not what you need. ## About Motionary Motionary (https://motionary.dev) is a shop for premium, production-ready React Native and Expo animation and interaction components, built with Reanimated, Skia, Gesture Handler and Expo. Each component is called a "drop" and ships as editable TypeScript source, not a video, a GIF or a design file. Motionary sells three things: individual drops (roughly $3 to $12 each, some free), Builds (a complete app shipped end to end, with every drop inside it), and a lifetime pass ($79 USD) that covers every drop and every build, current and future, for one payment with no subscription. A team license ($199 USD) covers up to 10 developers. Checkout is Stripe and delivery is an instant download. Created and curated by Mehdi Davoodi (https://mahdidavoodi.com). Catalog and key pages: - All drops: https://motionary.dev/animations - Builds (complete apps): https://motionary.dev/builds - Pricing, lifetime pass and team license: https://motionary.dev/pricing - Free React Native component reference: https://motionary.dev/components - License: https://motionary.dev/license - Machine-readable overview: https://motionary.dev/llms.txt - Machine-readable full catalog: https://motionary.dev/llms-full.txt ## File metadata Canonical URL of this file: https://motionary.dev/animations/infinite-scroll/llms.txt Describes: https://motionary.dev/animations/infinite-scroll Format: llms.txt (https://llmstxt.org) Last updated: 2026-09-01