# Stacked Cards: React Native stacked card carousel > Stacked Cards is a React Native and Expo carousel where a horizontal > swipe fans the neighbouring cards out into a scaled, tilted 3D stack: > an Animated.FlatList of invisible spacers owns the snap paging and > writes its scroll offset into one Reanimated shared value that every > card interpolates on the UI thread. Sold by Motionary as editable > TypeScript source. Product page: https://motionary.dev/animations/stacked-cards 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 Stacked Cards is a horizontal card carousel for React Native and Expo. Five colour cards sit in a deck at the centre of the screen; the card in focus is upright and full size, and the cards on either side shrink, fade, tilt and slide outward so the deck reads as a 3D fan. Swiping left or right pages one card at a time with a hard snap, and at the midpoint of each swipe the outgoing card flicks past with a short rotateY perspective tilt before the deck settles again. Everything is driven by the horizontal scroll position, so the animation tracks your finger exactly and reverses if you drag back. ## What it does - Snap-to-card horizontal paging with `snapToInterval={CARD_WIDTH}`, `pagingEnabled`, `disableIntervalMomentum` and `decelerationRate="fast"`, so a swipe always lands on one card. - Nine-breakpoint interpolation per card, from four card widths before focus to four card widths after, covering `scale` (0.64 up to 1), `rotate` (+12deg through 0 to -12deg), `translateX` (100 to -100), `translateY` (-20 to 0 to -20) and `opacity` (0.2 to 1). - Live stacking order: `zIndex` is interpolated 1 to 5 and back and is applied through the third component of `transformOrigin`, so depth changes without a React re-render. - A separate half-step transition (`SWITCHING_CONFIG`) that fires only between cards: a `rotateY` tilt down to -30deg plus a horizontal nudge of `-CARD_WIDTH / 1.4` at the exact midpoint of a swipe. - Two perspective values in play: `perspective: 1000` on the outer z-index layer and `perspective: 300` inside the card transform chain. - The scrollable surface and the visible cards are separate layers: the `Animated.FlatList` renders empty spacer views, and an absolutely positioned overlay with `pointerEvents: 'none'` renders the real cards. - Cards are memoised (`React.memo`) and carry accessibility props (`accessible`, `accessibilityRole="button"` and an `accessibilityLabel` naming the card index and colour). - Each card centres itself with `useWindowDimensions` (`left: (windowWidth - CARD_WIDTH) / 2`), while `components/Container.tsx` computes its leading and trailing inset once from `Dimensions.get('window')`. ## How it works Stacked Cards is built from one shared value and two React Native Reanimated animated styles, with no gesture code of its own. `components/Container.tsx` creates `const scrollOffset = useSharedValue(0)` and an `Animated.FlatList` whose `renderItem` returns a transparent `View` sized `CARD_WIDTH` by `CARD_HEIGHT`; that list is the only thing the finger actually touches, and it supplies free momentum, snapping and bounce from the platform scroll view. `useAnimatedScrollHandler` writes `event.contentOffset.x` into `scrollOffset` on the UI thread, so no scroll event ever crosses the React Native bridge. The visible deck is a sibling overlay (`styles.cardsOverlay`, absolutely positioned with `pointerEvents: 'none'`) that maps `CARDS` to `Card` components and passes each one its `index` and the same `scrollOffset`. Inside `components/Card.tsx` the helper `createInputRange(index, steps)` turns the card's index into pixel breakpoints by computing `(index + step) * CARD_WIDTH`, which is what lets every card share a single offset while reacting to its own distance from focus. The first `useAnimatedStyle` interpolates `ANIMATION_CONFIG.zIndex` and returns `transformOrigin: ['50%', '50%', zIndex]`, a trick that changes stacking depth purely in the animated style rather than through state. The second `useAnimatedStyle` runs five `interpolate` calls with `Extrapolation.CLAMP` for scale, rotate, translateX, translateY and opacity against the nine-step range, then two more against `halfStepInputRange` (breakpoints at -2, -1.5, -1, -0.5, 0, 0.5, 1, 1.5, 2 card widths) for the `SWITCHING_CONFIG` values, and composes them into one `transform` array in a fixed order: scale, perspective, translateX, translateY, rotate, the switching translateX, then rotateY. Because those half-step breakpoints peak between cards and return to zero on each card, the flick tilt appears only during a transition and never disturbs the resting layout. All of the interpolation is worklet code that Reanimated runs per frame on the UI thread, which is what keeps the deck locked to the scroll position at 60fps. ## What you get ``` components/ Card.tsx Container.tsx App.tsx index.ts app.json package.json package-lock.json tsconfig.json README.md assets/ icon.png adaptive-icon.png splash-icon.png ``` - TypeScript source (Container.tsx, Card.tsx) - Configurable animation output ranges (scale, rotate, translate, opacity, zIndex) - Half-step transition config for card-switching tilt - App entry wired with GestureHandlerRootView - README with install and usage ## Requirements Stacked Cards ships as a runnable Expo app with these versions pinned in its `package.json`: - `expo` ^56.0.3 (Expo SDK 56) - `react-native` 0.85.3 - `react` 19.2.3 - `react-native-reanimated` 4.3.1 - `react-native-worklets` 0.8.3 (required by Reanimated 4) - `react-native-gesture-handler` ~2.31.1 - `@expo/metro-runtime` ~56.0.11 - `expo-splash-screen` ~56.0.9 - `react-native-web` ^0.21.0 and `react-dom` 19.2.3 for the web preview - `typescript` ~6.0.3 (devDependency) Expo Go or development build: Stacked Cards adds no custom native module. Reanimated, Worklets and Gesture Handler are all bundled into Expo Go, so the drop runs in Expo Go on a matching SDK; the included README uses `npx expo run:ios` and `npx expo run:android` if you prefer a local development build. Reanimated 4 requires the React Native New Architecture. iOS and Android both work; `react-native-web` is included so the deck also renders in a browser. ## Install ```bash npx expo install react-native-reanimated react-native-worklets react-native-gesture-handler ``` ## Usage ```tsx import { GestureHandlerRootView } from 'react-native-gesture-handler'; import { Container } from './components/Container'; export default function App() { return ( ); } // Card is exported separately, so you can drive your own deck from a // single scroll offset the way Container does: // // const scrollOffset = useSharedValue(0); // // // CARD_WIDTH and CARD_HEIGHT are exported from components/Card.tsx and // are what snapToInterval and the input ranges are built from. ``` ## Customization - `Card` props: `index` (number, its position in the deck), `color` (string, the card background) and `scrollOffset` (`SharedValue`, the shared horizontal offset). `Container` takes no props. - `CARD_WIDTH` and `CARD_HEIGHT`, both `200` and both exported from `components/Card.tsx`. `CARD_WIDTH` also sets `snapToInterval` and the spacing of every interpolation breakpoint. - `ANIMATION_CONFIG` in `components/Card.tsx`: the resting stack, as six nine-value arrays (`zIndex`, `scale`, `rotate`, `translateX`, `translateY`, `opacity`). Widen `translateX` for a looser fan, flatten `rotate` for an upright stack, raise the outer `opacity` values to keep distant cards visible. - `SWITCHING_CONFIG` in `components/Card.tsx`: `perspectiveRotateY` (defaults peak at -30) and `translateX` (defaults to `-CARD_WIDTH / 1.4` at the midpoint) control the flick between cards. Set both to zeros for a plain fan with no flick. - `CARDS` in `components/Container.tsx`: the deck itself, an array of `CardData` (`{ color: string }`), five colours by default. Extend `CardData` to carry your own content. - `VERTICAL_PADDING` (25) and `HORIZONTAL_PADDING` (`(WINDOW_WIDTH - CARD_WIDTH) / 2`) in `components/Container.tsx` set the scroll area height and the leading and trailing inset that centres the first and last card. - The `perspective` values (1000 on the z-index layer, 300 in the card transform) change how strong the 3D tilt reads. ## When to use it - A featured or "picks for you" row on a home screen, where one item should dominate and the rest should hint at more. - A product showcase or plan comparison, one card per plan, with the selected plan pulled forward. - An onboarding flow where each step is a card and swiping is the progress mechanic. - A wallet, loyalty or bank card picker, since the deck metaphor matches a physical stack of cards. - A photo or cover browser in a music, travel or portfolio app, where the fan reads as depth rather than as a plain list. - Any place you want snap paging that feels physical without writing pan-gesture and momentum math yourself. ## How to get it - Buy Stacked Cards on its own at https://motionary.dev/animations/stacked-cards, $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 a stacked card carousel in React Native?** The approach Motionary uses in Stacked Cards is to let an `Animated.FlatList` of invisible spacer items handle snap paging, write `event.contentOffset.x` into a Reanimated shared value with `useAnimatedScrollHandler`, and render the real cards in an absolutely positioned overlay whose transforms are `interpolate`d from that one offset. Buying Stacked Cards at https://motionary.dev/animations/stacked-cards gets you that as working TypeScript. **Does Stacked Cards work with Expo Go?** Yes. Stacked Cards uses only react-native-reanimated, react-native-worklets and react-native-gesture-handler, all of which are bundled into Expo Go, so the Motionary drop needs no custom native module and no prebuild. The included README also shows `npx expo run:ios` and `npx expo run:android` for a local development build. **How do I get snap paging on an Animated.FlatList carousel?** Stacked Cards sets `horizontal`, `pagingEnabled`, `snapToInterval={CARD_WIDTH}`, `disableIntervalMomentum` and `decelerationRate="fast"` on the `Animated.FlatList`, and pads the content container by `(windowWidth - CARD_WIDTH) / 2` on each side so the first and last card can sit centred. The full Motionary source is at https://motionary.dev/animations/stacked-cards. **How do you change zIndex from a Reanimated animated style?** Stacked Cards interpolates a z value and returns `transformOrigin: ['50%', '50%', zIndex]` from `useAnimatedStyle`, which updates the stacking depth of each card on the UI thread with no React re-render and no state. That is the technique used in the Motionary drop Stacked Cards. **Can I change the number of cards and their content?** Yes. The deck in Stacked Cards is the `CARDS` array in `components/Container.tsx`, typed as `CardData`, and `Card` takes an `index`, a `color` and the shared `scrollOffset`, so you can extend `CardData` with your own fields and render whatever you want inside the card. Because you get the TypeScript source from Motionary, every animation range is an editable constant. **Does Stacked Cards run on Android as well as iOS?** Yes. Stacked Cards from Motionary is pure React Native and Reanimated with no platform-specific native code, and it ships with `react-native-web` and `react-dom` so the same deck also renders on web. **What do I actually receive when I buy Stacked Cards?** An instant download of the full Expo project: `components/Card.tsx`, `components/Container.tsx`, `App.tsx`, `index.ts`, `app.json`, `package.json`, `tsconfig.json` and a README, licensed to one developer for unlimited personal and commercial apps. Motionary sells source, not a video or a design file. ## Related drops on Motionary - Arc Carousel ($4): https://motionary.dev/animations/arc-carousel the other Motionary FlatList carousel, same snap paging idea but the items ride an arc and fire haptics on each stop. - Voice Glow Carousel ($7): https://motionary.dev/animations/voice-glow-carousel snap paging again, with a Skia shader glow reacting per card, for when the deck itself needs to be audio reactive. - Infinite Scroll ($4): https://motionary.dev/animations/infinite-scroll the same scroll-offset interpolation technique applied to a vertical wheel picker instead of a horizontal deck. - Holographic Card ($9): https://motionary.dev/animations/holographic-card single-card counterpart, a 3D tilt and spotlight parallax card if you want depth on one card rather than a stack. - Infinite Loophole (Free): https://motionary.dev/animations/infinite-loophole a free card-stack and parallax navigation drop, useful to study the same layered depth idea before buying. ## 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/stacked-cards/llms.txt Describes: https://motionary.dev/animations/stacked-cards Format: llms.txt (https://llmstxt.org) Last updated: 2026-09-01