react-native-screen-choreography
Shared elements. Connected screens. Dynamic trays.
Move real content between React Native screens and resizable trays without losing component state. Coordinate shared elements and supporting motion with one animation progress value.
Documentation · Get started · Examples · Dynamic trays
Watch: Gallery · Trips · Wallet
What you can build
- Shared element transitions: move several elements together, with one live content subtree per shared element. React state and context stay with the original owner.
- Coordinated motion: drive supporting content, reveals, and custom transitions from the same progress value.
- Interactive Back: connect your own gesture to transition progress, including cancellation. Native-stack swipe progress is not connected automatically.
- Dynamic trays: build flows inside a sheet that resizes with its content, expands to full screen, responds to the keyboard, and preserves forms and scroll position on Back.
Dynamic trays
A tray keeps a flow inside the current screen. Share elements between steps, let the sheet fit each view, and return to a previous step without rebuilding its state.
The example app includes two flows:
- Gallery Plus: shared photo and button elements move through plan selection and preview as the tray resizes.
- Wallet: change a payment draft from 25 to 250, open the full-screen recipient list, and go Back with 250 preserved.
Watch: Gallery Plus · Wallet tray
Trays use the optional /tray entry with Software Mansion bottom sheets and Keyboard Controller. Those dependencies are only required when using trays.
Build your first tray · Tray installation · Gallery source · Wallet source
Get started
npm install react-native-screen-choreography
The library includes native code and requires peer dependencies and a native rebuild. Choose the setup for your app:
Requirements: iOS or Android, React Native ≥0.81 with the New Architecture / Fabric, React ≥18, Reanimated ≥4, Worklets ≥0.8.3, and Teleport ≥1.2.2. Choose mutually compatible versions; these peer ranges are not a full tested compatibility matrix. Expo requires a development build; Expo Go is not supported.The bare example uses React Native 0.83; the Expo Router example uses Expo SDK 57. See the installation guide for navigation dependencies, Babel configuration, and native setup.
Pre-1.0: minor versions can introduce breaking changes. Check the release notes when upgrading.
Render once, share between screens
The source renders the content. The destination declares an empty, measurable target. The library moves the same native subtree through an overlay into that target using react-native-teleport.
import { SharedElement } from 'react-native-screen-choreography';
// Source screen: render content once.
<SharedElement id="hero" groupId="photo.aurora" style={styles.tile}>
<PhotoHero />
</SharedElement>;
// Destination screen: reserve its receiving bounds.
<SharedElement.Target id="hero" groupId="photo.aurora" style={styles.hero} />;
Pair both endpoints with the same id and groupId. The owner screen must remain mounted. Wrap routes in ChoreographyScreen and navigate with that group; the complete two-screen example covers provider placement, navigator configuration, and Back. For Expo Router, use the exports from react-native-screen-choreography/expo-router.
Explore the examples
Both apps share the Gallery, Trips, Wallet, and dynamic tray demos, including their defineTransition definitions:
- React Navigation example — bare React Native setup for iOS and Android.
- Expo Router example — native development-build setup.
- Shared demo source — screens, trays, and transition definitions used by both apps.
Documentation
| Build a feature | Reference | | -------------------------------------------------- | ------------------------------------------------ | | Your first transition | Components | | Transition recipes | Transitions | | Interactive Back | Navigation | | Dynamic trays | Hooks and utilities | | Readiness and loading | Troubleshooting |
For contributors: runtime architecture · contributing.

