rslabdocs

Card Expand

The App Store transition, tap a card, it becomes the screen, drag down to send it back.

ReanimatedGesture HandlerSource

Prerequisites

This animation is built on the following libraries. expo install pins the versions that match your SDK, and the CLI tells you exactly which ones are missing when you add the component.

npx expo install react-native-reanimated react-native-gesture-handler @shopify/react-native-skia expo-haptics react-native-safe-area-context @hugeicons/react-native @hugeicons/core-free-icons react-native-css

Install

npx @rslab/cli add card-expand

Usage

import { CardExpand, ExpandCard } from '@/components/CardExpand';

const CARDS: ExpandCard[] = [
  {
    id: 'focus',
    label: 'Featured',
    title: 'Deep Focus',
    subtitle: 'One line under the title.',
    body: 'The long text revealed once the card is fullscreen.',
    colors: ['#3b2f2a', '#8a5a3b'],
  },
];

<CardExpand cards={CARDS} />;

How it works

  • Measure the card. On tap, measureInWindow gives the card's rect in window coordinates. That rect is the entire shared element contract: the clone starts there and must land back there.
  • One progress drives everything. An overlay renders the same card face and a single progress value interpolates its rect from the slot to fullscreen, on a calm Apple-style bezier (0.32, 0.72, 0, 1), no spring. The body fade, the label offset and the background list zoom all read the same value, so nothing can desync.
  • Drag to dismiss. A pan shrinks the sheet while held. Past 140pt or a 900pt/s flick it releases into the close animation, reversed on the same curve.
  • Coordinate space. The overlay lives inside the component's container, translated by the container's window offset, so the sheet covers the whole screen even when mounted below a header.

Tuning

  • OPEN_TIMING (440ms) and CLOSE_TIMING (380ms), same bezier
  • CARD_RADIUS (28) and the display radius (55) in sheetStyle
  • Dismiss thresholds in the pan: 140pt distance or 900pt/s velocity
  • The list zoom (scale 0.95, opacity 0.65) in listStyle

On this page