Skip to content
Native Animation
Card Detail Expand animation preview

This preview uses fictional demo content. See the props below for the customization options available in this component.

npx nativeanimation add card-detail-expand
Carousel

Card Detail Expand

An expandable booking carousel with a shared image transition and configurable items, typefaces, surface color, and text color.

$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.

About this animation

An expandable booking carousel with a shared image transition and configurable items, typefaces, surface color, and text color.

Why this one

The artwork, card, and price surface share one reversible expansion progress instead of cutting between two screens. The price pill grows into the cream detail surface while its title and price travel into place. Scrolling then collapses the illustrated hero, keeping the vehicle name visible in the detail header. The booking button samples its color continuously from adjacent cards.

How it works

  1. onLayout measures the host container. Cards occupy 62% of its width and 48% of its height.
  2. A continuous shared carousel position drives perspective, scale, artwork parallax, neighbor shading, and button color.
  3. Gesture Handler races a horizontal pan against a tap. Press feedback has a separate shared value.
  4. One expansion progress drives the card bounds, hero, cream surface, title size, price size, and staggered detail content. A 650 ms (0.65, 0, 0.35, 1) curve runs forward or backward from the current position.
  5. A native scroll view drives the hero collapse and half-speed image parallax on the UI thread. The expanded viewport reserves its full height and the panel moves with a transform, so scrolling never resizes the scroll view or triggers React renders. A counter-transform keeps text movement one-to-one with the native scroll offset; fixed bottom padding keeps the content reachable while the panel extends below the host.
  6. A downward drag on the hero reverses expansion only when the detail scroll is at the top. The hero detector does not cover the scrollable body. The back button remains available at any scroll offset.
  7. Ref methods let the host orchestrate a demo without placing autoplay logic in the component.

Install

npx expo install expo-image react-native-gesture-handler react-native-reanimated react-native-worklets

Wrap your app in GestureHandlerRootView. Configure Reanimated and Worklets using the instructions for your Expo SDK. No new native modules or remote assets are needed in this project's Expo Go setup.

Usage

import { CardDetailExpand } from './card-detail-expand';

<CardDetailExpand
  items={[
    {
      id: 'coastal',
      name: 'Coastal Camper',
      image: require('./assets/coastal.jpg'),
      price: 96,
      color: '#E8783C',
      description: ['A cozy base for your next trip.', 'Fresh linens and a stocked kitchen included.'],
    },
  ]}
  onBook={(item) => startCheckout(item.id)}
/>
const ref = useRef<CardDetailExpandRef>(null);

<CardDetailExpand
  ref={ref}
  items={campers}
  title="Choose your camper"
  subtitle="Big Sur · 7 nights"
  nights={7}
  duration={650}
  cardWidthRatio={0.62}
  surfaceColor="#FFF4E2"
  textColor="#302537"
  fontFamily="YourInterfaceFont"
  mediumFontFamily="YourMediumFont"
  titleFontFamily="YourEditorialFont"
  monoFontFamily="YourNumberFont"
  onInteraction={stopAutoplay}
/>;
// Call from a host event or timer:
ref.current?.goTo(2);
ref.current?.open();

Props

PropTypeDefaultPurpose
itemsreadonly CamperCard[]RequiredUnique IDs, names, artwork, nightly prices, accents, descriptions, optional features and rating
titlestringChoose your stayCarousel heading
subtitlestringYour next adventureTrip context
brandReactNodeNoneHost-provided brand content
nightsnumber7Booking total multiplier
fontFamilystringSystemBody text
mediumFontFamilystringSystemInterface text
titleFontFamilystringSystemEditorial detail heading
monoFontFamilystringSystemTabular prices
surfaceColorstring#FFF4E2Detail surface
textColorstring#302537Foreground
durationnumber650Expansion duration in ms
cardWidthRationumber0.62Card width, constrained to 0.5–0.8
onIndexChange(index) => voidNoneSelection callback
onDetailChange(open, item) => voidNoneDetail state callback
onBook(item) => voidNoneHost checkout action
onInteraction() => voidNoneStop host autoplay
styleStyleProp<ViewStyle>NoneContainer overrides
testIDstringNoneTest selector

The ref exposes goTo(index), open(), close(), scrollTo(offset), and reset(). Calls to goTo are ignored while detail is expanded. Artwork should be bundled locally. Long descriptions remain scrollable; choose concise names so the single-line morph header fits small phones.

Compatibility

Built for Expo SDK 58, React Native 0.88.0, Reanimated 4.7.1, Worklets 0.13.0, and Gesture Handler 3.3. No Skia requirement. iOS, Android, and web are intended targets.

Accessibility

Browse by swiping, tapping neighboring cards, selecting a pagination control, or using previous/next buttons. All buttons have roles and labels; state changes are announced and the selection has a polite live region. Back is available without a drag. Read more provides a tap alternative to scrolling the collapsing hero. Reduced motion uses a 200 ms fade through the layout change and disables perspective, parallax, hero collapse, and press scaling. Prices do not roll.

Demo

Northwind uses the kit's compass tile and four local illustrations. Autoplay selects the second and third cards, opens at 1.9 seconds, scrolls, closes, and returns to the first card. Any direct interaction clears the timers. The checkout action records a trip confirmation locally.

The shared font loader exposes Geist Medium, not Geist SemiBold; the demo uses the available Medium face instead of introducing an unloaded font.

Icons: Lucide (ISC). Paths copied from the repository kit into icons.ts and rendered as SVG images. The Northwind brand and artwork belong to the demo only.