Skip to content

What is it? ​

react-native-shared-hero is a native shared element (hero) transition library for React Native's New Architecture (Fabric) on iOS and Android.

You wrap a view on screen A and a view on screen B in <SharedHero id="...">. When screen B mounts (or screen A unmounts), the native coordinator captures both views, hides the real endpoints while the transition is in flight, and animates a clone across a window-level overlay at the display's native refresh rate (60 fps or 120 fps ProMotion).

Showcase ​

AndroidiOS

Why another shared element library? ​

Existing shared element solutions in React Native run into three recurring pain points on the New Architecture:

1. Navigator lock-in

Many implementations hook directly into react-native-screens stack transitions. That breaks as soon as you present a native modal, a transparent modal, a form sheet, a core React Native <Modal>, or an in-place card expansion without navigation.

2. View-hierarchy clipping

When a flying clone is reparented inside a screen container or navigation view controller, parent overflow: 'hidden' bounds or sheet presentation frames clip the element mid-flight.

3. Thumbnail blur on zoom-in

Scaling a small list thumbnail bitmap up to a full-width detail header looks blurry. react-native-shared-hero detects image-only heroes and swaps in the destination's full-resolution image as soon as it finishes decoding.

react-native-shared-hero takes a different architectural approach:

  • Window-level overlay: On iOS, flights render inside a transparent, non-interactive UIWindow (windowLevel = .alert + 1, isUserInteractionEnabled = false) that sits above every UIViewController, modal, and sheet. On Android, flights render in the target window's DecorView.overlay (ViewGroupOverlay). Nothing in your React tree can clip the flying element.
  • Zero router coupling: Pairing is driven by native view mount, layout, and unmount lifecycles within a short matching window. It works identically with React Navigation, Expo Router, custom state toggles, or React Native's built-in <Modal>.
  • Zero idle cost: When no transition is running, the overlay holds zero child views (backgroundColor = .clear, isUserInteractionEnabled = false), fallback snapshot caches are strictly bounded with an LRU policy, and views skip redundant offscreen renders when nothing has changed.

Feature matrix ​

CapabilityiOSAndroidNotes
Fabric (New Architecture)YesYesBuilt as a Fabric ViewManager / RCTViewComponentView
mode="snapshot"YesYesFast bitmap capture, translate + scale + fade
mode="morph"YesYesInterpolates bounds, borderRadius, backgroundColor, and clip shape
motionPath="linear" / "arc"YesYesStraight line or Material quadratic Bezier arc
Duration + cubic-Bezier easingYesYeslinear, easeIn, easeOut, easeInOut, standard, emphasized
Native spring physicsYesYesCASpringAnimation on iOS, SpringAnimation on Android
Fade curves (fadeMode)YesYescross, in, out, through
High-res destination image upgradeYesYesSharp zoom-in when both endpoints wrap a single <Image>
Text reflow protectionYesYesScales snapshots proportionally instead of cropping re-wrapped glyphs
Interactive iOS swipe-backYesN/AAutomatically tracks interactivePopGestureRecognizer progress
Mid-flight takeoverYesYesInterrupts an active flight smoothly from its live mid-air rect
FlatList / FlashList recyclingYesYesCleans up stale id buckets when cells recycle

Requirements ​

  • React Native: 0.76+ with the New Architecture (Fabric) enabled (tested through React Native 0.82).
  • iOS: iOS 14.0+ (works with both static linkage and use_frameworks!).
  • Android: minSdkVersion 24+, Kotlin + AndroidX dynamicanimation.
  • Expo: Works in Expo custom development builds (npx expo run:ios / npx expo run:android / EAS Build). Not available in Expo Go because it includes custom native code.

Released under the MIT License.