Animating Product Favorites in Shop

When a buyer favorites a product in Shopify's Shop app, the product image drops into the heart icon in the bottom navigation tab. That transition feels smooth because of a carefully sequenced animation driven by a single shared value in React Native. Here's how the implementation works.

The motion spec for this feature breaks the transition into seven distinct steps. The product thumbnail fades in from 0 to 1 opacity while scaling from 0 to 1.2, then settles back to scale 1. After a 50 ms pause, it moves downward and disappears instantly. The favorites tab bar icon then reacts with its own sequence of downward movements, color changes from white to purple and back, and bounces back to its original position.

Each step has its own duration and easing curve from the motion spec:

One Shared Value Drives the Sequence

The Shop app uses Reanimated for animations. Rather than creating separate shared values for each property, the entire sequence uses one shared progress value that moves from 0 through 7, matching the steps above. Each animated property maps that progress value through interpolation to its target values for each step.

Interpolation maps an input range to an output range. With clamping, values outside the input range hold at the nearest output boundary. That is essential here: the thumbnail's opacity interpolates from 0 to 1 over steps 0 to 1, then clamps at 1 for all remaining steps so it stays fully visible until the moment it needs to vanish.

The thumbnail's scale follows a similar pattern, interpolating from 0 to 1.2 between steps 0 and 1, then from 1.2 to 1 between steps 1 and 2. After step 2, it clamps at 1.

Vertical translation moves the thumbnail from position -60 to -34 between steps 2 and 3, which positions it halfway behind the tab bar. For the instant disappearance at step 3, no interpolation is used — the opacity jumps directly to 0 instead of animating a fade-out.

Bouncing the Heart Icon

For the tab bar icon, the filled purple heart sits on top of the white unfilled heart. A simple opacity animation on the filled heart, interpolating from 0 to 1 and back to 0 over steps 3 through 5, creates the color transition without animating the color property itself.

The bounce is handled separately with vertical translation. Between steps 3 and 7, the icon moves down and up repeatedly, producing the bouncing effect that signals the product has been added.

Why the Match Cut Matters

The single shared value creates a match cut: as the product thumbnail moves down and disappears, the heart icon's downward movement begins on exactly the same frame. The user's eye follows the downward motion from the thumbnail straight into the icon, associating the two actions.

An earlier approach used setTimeout to start the icon animation after the thumbnail finished. When the JavaScript thread was busy, the timer delayed the second animation and broke the transition. Reanimated's withDelay avoids this by keeping timing on the UI thread, but the shared-value approach eliminates the sequencing problem entirely — both animations are already synchronized by construction.