What This System Is
Bounds Transitions animate matched geometry across screens by measuring a source boundary and a destination boundary, then moving screen A and screen B together so the result reads like shared element motion.
If you are specifically looking for true shared element transitions, wait for Reanimated Shared Element Transitions to become production-ready. This package's bounds system is a different approach.
Boundary Pattern
Use Transition.Boundary for both interactive and passive boundaries.
When onPress is present, the boundary behaves like a pressable source. When onPress is omitted, it behaves like a passive measured view.
TSX
Transition.Boundary.View and Transition.Boundary.Trigger still exist as deprecated aliases, but new code should use Transition.Boundary.
For the high-level bounds(id).navigation.zoom() helper, the destination boundary is optional unless the zoom should target a specific destination element. See Zoom.
Nested Measurement with Boundary.Target
Use Transition.Boundary.Target when the pressable owner is larger than the visual element you want to measure.
TSX
This keeps the row as the interaction owner while limiting measurement to the nested artwork.
The bounds() Accessor
Inside screenStyleInterpolator, call bounds(id) to scope the accessor to one boundary identity.
This accessor replaces the store-shaped bounds helpers from v3.8. The removal is source-breaking for callers of getMeasured, getSnapshot, getLink, interpolateStyle, interpolateBounds, or BoundsLink.compute. See New in 3.9 for the full migration table.
TSX
The scoped accessor exposes:
bounds(id).styles(options)for render-ready animated stylesbounds(id).values(options)for numeric geometrybounds(id).link(id?)for inspecting the active source/destination linkbounds(id).navigation.zoom(options)for the built-in zoom recipebounds(id).navigation.reveal(options)for the built-in reveal recipe
Bound identities can be a string, a number, or an object with { id, group }.
TSX
Bounds Options
Pass identity to bounds(), then pass compute options to styles() or values().
| Option | Values | Notes |
|---|---|---|
method | "transform" | "size" | "content" | Matching strategy |
target | "bound" | "fullscreen" | MeasuredDimensions | Destination target |
anchor | "topLeading" through "bottomTrailing" | Matching anchor point |
scaleMode | "match" | "none" | "uniform" | Aspect-ratio behavior |
offset | { x?: number; y?: number } | Add live x/y offsets from gestures, scroll, or animation state |
progress | number | Custom progress driver for the bounds interpolation |
motion | BoundsMotion | Replace the generated transform path without reimplementing measurement |
gestures | { x?: number; y?: number } | Deprecated alias for offset |
space | "relative" | "absolute" | absolute is mainly for navigation helpers and custom renderers |
Numeric Bounds with values()
Use styles() when you want the library to return the final animated style object.
Use values() when you want the same measured geometry but need to compose the final style yourself.
TSX
Zoom and Reveal
For navigation-style bounds transitions, use the navigation helpers:
TSX
For masked source-to-container transitions, use navigation.reveal():
TSX
See Zoom and Reveal for the full setup.
Groups
group is for flows where the active member can change inside the same collection, such as galleries, paged detail screens, or retargeted list/detail flows.
TSX
The group keeps track of the active member id so the transition stays aligned as focus moves between items in the same collection.
Live Payload Handoff
Use handoff when the same live payload should move between matching boundaries instead of remounting on each screen.
Live payload handoff is experimental in v3.9. It works well for focused flows, but native-backed content and rapid navigation can still expose platform-specific lifecycle or compositing edge cases.
TSX
Every matching boundary that should participate in the handoff should set handoff. The destination defines the receiving bounds; it does not need to render a second copy of the live child.
Use escapeClipping when a boundary needs to render outside local clipping or layout constraints during the transition.
TSX
handoff and escapeClipping use react-native-teleport under the hood. Install the supported version when using either prop:
The supported range is >=1.1.0 <1.1.11. Version 1.1.11 is not compatible with continuously animated boundary hosts.
Test handed-off video on physical Android devices. A SurfaceView may not obey portal clipping or transforms, while a TextureView participates in normal view composition but can briefly flicker while its native surface moves between hosts. For Expo Video, surfaceType="textureView" is usually the correct choice when clipping and transforms matter.
See Caveats & Trade-offs for the current handoff support boundary.
Bounds with Offsets
Because styles() and values() accept an offset option, you can feed any live x/y values into the matched transform.
TSX
The older gestures option still works as a deprecated alias. Use offset for new code because the values can come from gestures, scroll, animation state, or any other x/y source.
Bounds with a Custom Progress Driver
By default, bounds use the visual frame progress, which includes live gesture movement.
Pass transitionProgress when the geometry should stay on the committed transition path while you layer gesture motion separately:
TSX
This is the replacement for older gestureProgressMode: "freeform" patterns in custom bounds animations.
Link Inspection
Use link() when you need to inspect the active source/destination pair.
TSX
Most animations should use styles(), values(), or the navigation helpers instead of reading the link directly. link() is useful when you are building custom choreography on top of the same measured pair.
Troubleshooting
Bounds Mismatch
Source, destination, and interpolator lookups must all resolve to the same boundary identity.
TSX
If you use groups, the same rule applies to the group + id pair.