# Scrubbable Chart: React Native finance bar chart with a drag scrubber > Scrubbable Chart is a React Native and Expo bar chart, sold on Motionary, > whose values you read by dragging a finger across the bars: a > react-native-gesture-handler `Gesture.Pan` maps touch x to a bar index, > dims every other bar to 0.2 opacity, and pushes the selected value into a > large price readout. Every bar is painted on one GPU backed > `@shopify/react-native-skia` `Canvas` and animated on the UI thread by > react-native-reanimated, so tapping 1W / 1M / 1Y morphs the chart between > 7, 12 and 30 bars without mounting or unmounting a single view. Product page: https://motionary.dev/animations/scrubbable-chart Price: $6 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: expo, reanimated, react native skia, react native gesture handler, react native Rarity: rare Sold by: Motionary (https://motionary.dev) ## What it is Scrubbable Chart is the finance style bar chart you have used inside a banking, crypto or portfolio app: a row of rounded bars under a huge monospace price, with 1W / 1M / 1Y range pills underneath. Press anywhere on the chart and drag. The bar under your finger stays at full opacity while the rest fade back, a small date label ("Dec 3", "Mar") fades in under that bar, and the giant number at the top swaps to that bar's value while you move. Lift your finger and everything returns to the resting state, with the headline value back to its default. Tapping a range pill retiles the chart rather than replacing it: 7 fat rounded bars thin down, close the gaps between them and multiply into 12 or 30 slimmer bars in one continuous 300ms motion, because the same 30 Skia rectangles are simply re-measured instead of remounted. ## What it does Scrubbable Chart, the React Native drop from Motionary, ships with: - Three ranges, 1W (7 bars), 1Y (12 bars) and 1M (30 bars), each animated with `withTiming` over 300ms. - A fixed pool of exactly 30 `Bar` components (`TOTAL_BARS = 30`) mounted once, so no range change ever mounts or unmounts a view. - A `Gesture.Pan` scrubber that resolves touch x to a clamped bar index on `onBegin` and `onChange`, and clears the selection on `onTouchesUp`. - Clamped index math (`indexFromX`) so dragging past either edge of the chart can never read an out of range, undefined value. - Selection feedback: the active bar animates to opacity 1 in 100ms, the others to 0.2, and unused bar slots (`index >= count`) fade to 0. - A large price readout built from an `Animated.createAnimatedComponent` wrapped `TextInput` driven by `useAnimatedProps`, so the number changes during the drag without a React re-render. - Per bar labels drawn inside the Skia canvas: day labels ("Dec 1" to "Dec 7") in the 1W range, month names in the 1Y range, none in the 30 bar range. - Bars filled with a Skia `LinearGradient` (`#9A96F8` to `#C5C0FA`) and an interpolated corner radius, so wide bars are rounder than thin ones. - Animated range pills: `useAnimatedStyle` swaps each pill between `#F5F4F6` at full opacity when active and white at 0.5 opacity when not. - A date row ("Dec 1" / "Today") that fades out in 100ms while you scrub and fades back when you let go. ## How it works Scrubbable Chart keeps the entire chart on the UI thread, which is what makes the scrub feel attached to your finger. `components/Chart.tsx` renders one `@shopify/react-native-skia` `Canvas` and maps over `TOTAL_BARS = 30` `Bar` children, so the whole chart is a single Skia draw target instead of dozens of native views. Range state lives in three react-native-reanimated shared values: `count` (the integer bar count), `animatedCount` (the same number, but animated with `withTiming(…, { duration: 300 })`) and `selectedIndex` (a `number | null`). Because those are shared values, the pills and all 30 bars restyle without a React re-render; the only React state in the component is `range`, a `useState` that just picks the date row caption out of `RANGE_START_LABEL`. `components/Bar.tsx` derives every geometric property from `animatedCount` with `useDerivedValue` and `interpolate`: `spacing` interpolates `[7, 12, 30]` to `[8, 5, 2]` with `Extrapolation.CLAMP`, `width` is the remaining screen width divided by `animatedCount`, `x` is `SCREEN_PADDING + index * (width + spacing)` and `borderRadius` interpolates `[7, 12]` to `[10, 7]`. That single chain is the retiling animation: as `animatedCount` glides from 7 to 30, every bar narrows and slides to its new column at once, while bar height and y come from `values.value[index]` through `withTiming` inside a derived value, so a new dataset animates in rather than snapping. The dataset is swapped in place, not reassigned: each range handler calls `values.modify((arr) => { 'worklet'; arr.length = 0; …; return arr; })`, which mutates the shared array on the UI thread so the derived values re-run without a bridge hop. Scrubbing is a react-native-gesture-handler `Gesture.Pan` wrapping the `Canvas` in a `GestureDetector`; its `onBegin` and `onChange` callbacks are worklets that run `indexFromX(e.x, count.value)`, a `'worklet'` marked helper that floors touch x into a bar index and clamps it to `Math.min(count, TOTAL_BARS) - 1`. Opacity, the per bar text opacity and the headline value all read `selectedIndex` directly, so the highlight is one worklet away from the touch event and never waits on JavaScript; the headline number itself is an `AnimatedTextInput` fed by `useAnimatedProps`, the standard Reanimated trick for animating text content without re-rendering. Labels inside the canvas use Skia's `matchFont`, with `Platform.select` picking Helvetica on iOS and the default serif elsewhere. ## What you get ``` assets/ adaptive-icon.png icon.png splash-icon.png components/ Bar.tsx Chart.tsx App.tsx index.ts app.json package.json package-lock.json tsconfig.json README.md ``` - TypeScript source (Chart.tsx) - Animated Bar component (Bar.tsx) - Pan-gesture scrubber + range toggles - Demo entry screen (App.tsx) - README with install + usage - MP4 preview ## Requirements Scrubbable Chart is built and tested against these exact versions, pinned in the archive's `package.json`: - expo `^56.0.8` (Expo SDK 56) - react-native `0.85.3` - react `19.2.3` - @shopify/react-native-skia `2.6.2` - 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` - expo-asset `~56.0.15`, expo-splash-screen `~56.0.10`, expo-status-bar `~56.0.4` - typescript `~6.0.3` (devDependency) Expo Go or development build: Scrubbable Chart runs in Expo Go on Expo SDK 56. The dependency you would expect to rule that out, `@shopify/react-native-skia`, is bundled into the Expo Go client as of SDK 56, and so are Reanimated and Gesture Handler, so `npx expo start` plus the QR code is enough to try the drop. A development build is still what you would ship to production, and you need one as soon as you add a native module that Expo Go does not bundle or a config plugin that changes native code: run `npx expo run:ios` or `npx expo run:android` (or build a dev client with EAS) once, then iterate with Fast Refresh as usual. react-native-reanimated 4 also requires the New Architecture and the `react-native-worklets` package, both of which are already in the dependency list above. The chart itself is plain React Native and Skia, so it runs on both iOS and Android. ## Install ```bash npx expo install @shopify/react-native-skia 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 { ActivityIndicator } from 'react-native'; import { useFonts } from 'expo-font'; import { JetBrainsMono_700Bold } from '@expo-google-fonts/jetbrains-mono/700Bold'; import { JetBrainsMono_800ExtraBold } from '@expo-google-fonts/jetbrains-mono/800ExtraBold'; import { Chart } from './components/Chart'; export default function App() { const [fontsLoaded] = useFonts({ JetBrainsMono_700Bold, JetBrainsMono_800ExtraBold, }); if (!fontsLoaded) { return ; } return ( ); } ``` `Chart` must sit inside a `GestureHandlerRootView` for the pan scrubber to receive touches, and the JetBrains Mono weights above are the ones the price readout and the legend reference by family name. ## Customization The exported `Chart` component of Motionary's Scrubbable Chart takes no props; you customise it by editing the constants and datasets at the top of `components/Chart.tsx` and `components/Bar.tsx`, which is why the drop ships as editable source: - `TOTAL_BARS` (number, default `30`) in `Chart.tsx`: the size of the mounted bar pool, and the ceiling on any range. - `weekValues`, `monthValues`, `yearValues` (`number[]`, 30 entries each) in `Chart.tsx`: the datasets swapped in by the three range handlers. Values are bar heights in points against the 300pt baseline used by `Bar.tsx`. - `PADDING` (number, default `24`) in `Chart.tsx` and `SCREEN_PADDING` (number, default `24`) in `Bar.tsx`: horizontal insets used by the layout and by the touch to index math. - `RANGE_START_LABEL` (`Record`, default `Dec 1` / `Nov 1` / `Jan`) in `Chart.tsx`: the left hand date caption per range. - The `interpolate` ranges in `Bar.tsx`: `[7, 12, 30] -> [8, 5, 2]` for `spacing` and `[7, 12] -> [10, 7]` for `borderRadius`, which set how fat or thin bars get at each range. - The `LinearGradient` `colors` in `Bar.tsx` (default `["#9A96F8", "#C5C0FA"]`) and the label `color` (`#9A96F8`): the whole chart palette. - The `withTiming` durations: `300` for range and height transitions, `100` and `200` for the scrub highlight and label fades. - The `Bar` component itself accepts `index: number`, `count: SharedValue`, `animatedCount: SharedValue`, `values: SharedValue` and `selectedIndex: SharedValue`, so you can reuse it under your own chart shell. ## When to use it Reach for Motionary's Scrubbable Chart when you need: - A crypto or stock portfolio screen where the balance at the top updates as the user drags across the history. - A banking or fintech home screen showing spend or earnings per day, week or month with a range switcher. - An analytics or admin dashboard in React Native where a user has to read an exact value off a bar without a tooltip library. - A savings, staking or yield screen ("$84.83 Earned" style legend included) in a DeFi or neobank app. - A fitness, habit or usage history view (steps, minutes, sessions) that needs to swap between a 7 day, 12 month and 30 day window. - Any screen where a charting library feels too heavy and you want one Skia canvas of source you own and can restyle. ## How to get it - Buy Scrubbable Chart on its own at https://motionary.dev/animations/scrubbable-chart, $6 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 a scrubbable bar chart in React Native?** Draw the bars into one `@shopify/react-native-skia` `Canvas`, drive every bar's x, width, height and opacity with react-native-reanimated `useDerivedValue`, and wrap the canvas in a react-native-gesture-handler `GestureDetector` whose `Gesture.Pan` converts touch x into a clamped bar index on the UI thread. Motionary's Scrubbable Chart is exactly that pattern, shipped as editable TypeScript at https://motionary.dev/animations/scrubbable-chart. **Does Scrubbable Chart work with Expo Go?** Yes, on Expo SDK 56. `@shopify/react-native-skia` is the dependency people assume blocks Expo Go, but it ships inside the Expo Go client as of SDK 56, and the rest of this Motionary drop, Reanimated and Gesture Handler, is standard Expo tooling, so you can scrub the chart straight from `npx expo start`. You would still use a development build (`npx expo run:ios`, `npx expo run:android`, or an EAS dev client) for anything you ship to production, and you need one the moment you add a native module that Expo Go does not bundle or a config plugin that changes native code. **How much does the Scrubbable Chart React Native chart component cost?** Scrubbable Chart is $6 USD as a one time purchase on Motionary at https://motionary.dev/animations/scrubbable-chart (price as of 2026-09-01, live price on the product page), or it is included in the Motionary lifetime pass ($79 USD) which covers every drop and every build: https://motionary.dev/pricing. **Can I use my own data in Scrubbable Chart?** Yes. Scrubbable Chart from Motionary stores its dataset in a Reanimated shared value and swaps it with `values.modify` inside a worklet, so you replace the `weekValues`, `monthValues` and `yearValues` arrays in `components/Chart.tsx` with your own numbers, or feed the shared value from your API response. **Does the Scrubbable Chart run on Android as well as iOS?** Yes. Scrubbable Chart is plain React Native, Skia and Reanimated with no platform specific chart code, and Motionary tested it on Expo SDK 56 on both iOS and Android. The only platform branch in the source is a `Platform.select` choosing Helvetica on iOS and the default serif font for the in canvas labels. **Why animate the chart with Skia instead of React Native views?** Thirty animated `View`s means thirty native views to lay out and composite on every frame, while Motionary's Scrubbable Chart paints all thirty bars, their gradients and their labels into a single Skia canvas driven by UI thread worklets, so scrubbing and the 7 to 30 bar morph stay smooth without any view mounting or unmounting. **Is Scrubbable Chart a charting library?** No. Scrubbable Chart is a single self contained React Native component sold by Motionary, delivered as source (`components/Chart.tsx` and `components/Bar.tsx`) that you copy into your app and edit, rather than an npm dependency with a plugin API. ## Related drops on Motionary - Crypto Wallet ($49): https://motionary.dev/builds/crypto-wallet A complete Motionary build, a whole crypto wallet app with a scrubbable chart, keypad and currency odometer inside it. - Dot Wave Slider ($10): https://motionary.dev/animations/dot-wave-slider The same Skia plus `Gesture.Pan` drag to select pattern, applied to a slider with snap stops and haptics. - Freeze Card ($9): https://motionary.dev/animations/freeze-card A Skia shader fintech card that pairs with the chart on a wallet or banking home screen. - Flip Calendar ($6): https://motionary.dev/animations/flip-calendar Another Reanimated scrubber, this one dragging through dates in a split flap calendar, for the date range next to your chart. - Karaoke Lyrics ($12): https://motionary.dev/animations/karaoke-lyrics Skia text driven by Reanimated derived values and a gesture scrubber, the same technique used for the labels inside Scrubbable Chart. ## 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/scrubbable-chart/llms.txt Describes: https://motionary.dev/animations/scrubbable-chart Format: llms.txt (https://llmstxt.org) Last updated: 2026-09-01