Skip to content
Native Animation
Add to Cart Fly animation preview

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

npx nativeanimation add add-to-cart-fly

Add to Cart Fly

An add-to-cart flight with image trails and a rolling count, with configurable product image, copy, fonts, and accent 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 add-to-cart flight with image trails and a rolling count, with configurable product image, copy, fonts, and accent color.

Why this one

The actual product flies along a quadratic Bézier curve rather than sending a generic dot along a straight line. Three time-delayed copies preserve the source artwork’s proportions and make its path readable; the destination responds with a physical pop, an expanding teal ring, and rolling digits. Missing size selection gets a local shake and an explicit validation message. Up to three flights can overlap without blocking another tap. The trail clears at arrival, freeing its slot for another addition.

How it works

  1. onLayout measures the component. Product and destination coordinates use that container's width and height, with an 80-point bag margin that keeps even the expanding arrival ring outside the host close-button region.
  2. Each of three flight slots owns one normalized 0–1 progress value that advances linearly over 620 milliseconds. The easing curve applied to that timeline derives quadratic position, rotation, scale, and trails sampled 40, 80, and 120 milliseconds earlier.
  3. The main copy arrives at 620 milliseconds. A UI-thread reaction springs the bag and expands its ring over 300 milliseconds; scheduleOnRN updates quantity and calls onAdd once.
  4. Digit columns roll only during their own carry. Distance-based opacity prevents two crisp digits from sharing the badge. Quantity updates and animation start together in a layout effect.
  5. A Gesture Handler tap springs a separate pressure value to 0.97 and starts the flight from onEnd. The button changes from idle to flying, then added, and back to idle after 1,400 milliseconds. Another accepted tap starts another flight immediately.
  6. The demo selects US 10 at 550 milliseconds and launches at 1,000 milliseconds, placing arrival and celebration within the first three seconds. Later it demonstrates three overlapping flights. All demo timers are cleaned up.

Install

npx expo install expo-image @shopify/react-native-skia react-native-gesture-handler react-native-reanimated react-native-worklets

Wrap the application in GestureHandlerRootView. Configure the Reanimated Worklets plugin as required by your host project. For web, load Skia's CanvasKit before rendering this component; use your Expo project's existing Skia web setup. Demo-only branding also uses expo-linear-gradient.

Icons: Lucide (ISC). Copied icon paths are included in icons.ts.

Usage

import AddToCartFly from './add-to-cart-fly';

export function ProductScreen() {
  return <AddToCartFly image={require('./assets/shoe.png')} />;
}

Customize the screen and drive it externally:

import { useRef } from 'react';
import AddToCartFly, { type AddToCartFlyRef } from './add-to-cart-fly';

export function ProductScreen() {
  const product = useRef<AddToCartFlyRef>(null);
  return (
    <AddToCartFly
      ref={product}
      image={require('./assets/shoe.png')}
      title="Daily Runner"
      subtitle="Made for your morning miles"
      price="$120.00"
      sizes={['7', '8', '9', '10', '11', '12']}
      flightDuration={620}
      accentColor="#0F766E"
      onAdd={(count, size) => saveBag({ count, size })}
    />
  );
}

The ref exposes selectSize(size), add(), and reset(). reset() cancels pending flights, clears validation and selection, and restores initialCount. Autoplay belongs to the demo. onAdd is a local arrival notification; connect it to your own cart persistence and error handling.

Props

PropTypeDefaultDescription
imageImageSourcePropTypeRequiredTransparent local product artwork.
titlestringRunning shoeProduct heading.
subtitlestringLightweight daily trainerSupporting description.
pricestring$128.00Formatted price.
sizesstring[]US 7–12Available sizes; the demo uses six.
initialCountnumber2Starting bag quantity.
flightDurationnumber620Flight time in milliseconds, minimum 180.
addedDurationnumber1400Confirmation dwell in milliseconds.
accentColorstring#0F766EBadge accent.
backgroundColorstring#F5F5F2Screen background.
fontFamilystringSystemBody and control typeface.
titleFontFamilystringSystemDisplay typeface.
monoFontFamilystringSystemQuantity and price typeface.
brandReactNode—Host-provided brand lockup.
addLabelstringAdd to bagPrimary action text and label.
addedLabelstringAddedConfirmation text.
chooseSizeLabelstringChoose a sizeValidation message.
onAdd(count, size) => void—Called once per arrival.
onSizeChange(size) => void—Called on size selection.
onBack() => void—Host back navigation.
onBagPress() => void—Host bag navigation.
styleStyleProp<ViewStyle>—Outer container styling.
testIDstring—Outer test identifier.

Compatibility

Expo SDK 58, React Native 0.88.0, Reanimated 4.7.1, Worklets 0.13.0, and Skia 2.14.0. Uses bundled Expo Go native modules. iOS, Android, and web are intended targets.

Accessibility

Size pills, back, bag, and primary action expose button roles and labels. Each size exposes its selection state. Size errors use a polite live region. The primary action supports the screen-reader activate action as well as tapping. Hit areas are at least 44 points in the six-size mobile layout. With reduced motion, additions complete immediately, badge changes crossfade, and button text crossfades without translation. Flight, trails, ring, bag pop, pressure scaling, and validation shake stop.