Navigation Transitions

Reveal

Use bounds(id).navigation.reveal() for masked, source-to-container navigation reveal transitions.

What This Helper Is

navigation.reveal() is the high-level bounds helper for container-style navigation transitions.

It uses the same boundary link system as bounds() and navigation.zoom(), but instead of animating a floating matched element above the screen, it scales and masks the destination content from the source boundary into the destination container.

Use it when the destination screen should feel like it is revealed from the tapped source, especially for card, photo, or media-detail flows.

Reveal requires three pieces: a source boundary, a matching destination boundary, and a navigation interpolator that calls navigation.reveal().

Source Setup

Mark the source with Transition.Boundary and pass the reveal id through your navigation params.

TSX

1import Transition from "react-native-screen-transitions";
2
3<Transition.Boundary
4 id={item.id}
5 onPress={() => {
6 navigation.navigate("Detail", { revealId: item.id });
7 }}
8>
9 <Image source={item.image} style={styles.thumbnail} />
10</Transition.Boundary>

Destination Setup

The destination screen must render a matching boundary for the same id. That destination boundary is the real container target for the reveal.

TSX

1function DetailScreen() {
2 return (
3 <Transition.Boundary id={item.id}>
4 <Image source={item.image} style={styles.hero} />
5 </Transition.Boundary>
6 );
7}

If the target element is nested inside a larger pressable or layout owner, use Transition.Boundary.Target inside the boundary owner to narrow the measured region.

Enable navigationMaskEnabled on the destination screen, then call navigation.reveal() from its screenStyleInterpolator and read the id from the active route params.

TSX

1<Stack.Screen
2 name="Detail"
3 component={DetailScreen}
4 options={{
5 navigationMaskEnabled: true,
6 gestureEnabled: true,
7 gestureDirection: ["vertical", "horizontal"],
8 screenStyleInterpolator: ({ active, bounds }) => {
9 "worklet";
10
11 const id = active.route.params?.revealId;
12 if (!id) return null;
13
14 return bounds(id).navigation.reveal({
15 borderRadius: 58,
16 borderContinuous: true,
17 maxSensitivity: 0.8,
18 velocityDepth: 0.5,
19 });
20 },
21 }}
22/>

Reveal is intentionally opinionated: navigation.reveal() only works with the static navigationMaskEnabled screen option enabled, and that mask requires @react-native-masked-view/masked-view. The helper accounts for Android and iOS mask performance internally, but if you need the lightest possible path, use navigation.zoom() instead; zoom does not require masked view.

Install @react-native-masked-view/masked-view; without it, navigation mask styles cannot render.

Gesture Behavior

Reveal reads the active gesture state from the transition runtime:

  • pan directions can drag the revealed container away from the target
  • active.gesture.velocity affects the dismiss handoff scale
  • active.gesture.handoff keeps release-time values available while live gesture values reset

TSX

1options={{
2 gestureEnabled: true,
3 gestureDirection: ["vertical", "horizontal"],
4}}

Reveal uses transitionProgress internally for the bounds path, so drag movement can affect the live gesture values without dragging the source-to-destination geometry off its transition path. Use active.gesture.raw if you derive dynamic runtime options such as gestureSensitivity from gesture movement.

Options

Pass options directly to navigation.reveal() when you need to tune the opinionated defaults:

borderRadius

Destination mask border radius. Reveal interpolates from the measured source radius to this value.

typedefaultrequired
numberplatform defaultNo

borderContinuous

Uses React Native's continuous border curve for the reveal mask.

typedefaultrequired
booleantrueNo

maxSensitivity

Highest gesture sensitivity reveal applies before it reduces sensitivity during deeper drags.

typedefaultrequired
number0.8No

velocityDepth

Velocity-driven depth for the dismiss scale orbit. Set 0 to remove the velocity depth effect.

typedefaultrequired
number0.5No

backgroundScale

Scales the unfocused background content while the reveal runs above it.

typedefaultrequired
number0.9375No

shouldBackgroundScaleResetOnSettled

Restores the unfocused background content to scale 1 once the reveal is visually settled. This keeps the idle screen unmodified, so the next drag or programmatic dismiss can take a fresh measurement from the real screen geometry instead of from a scaled background.

typedefaultrequired
booleantrueNo

disablePointerEventsTillElementTransition

Blocks pointer-event pass-through on the inactive content until the source element handoff reaches progress 0.25. This is intentional and most users cannot react fast enough to swipe during that brief handoff. Set false to disable the guard and keep the default behavior that allows pointer events to pass through.

typedefaultrequired
booleantrueNo

maskSizingMode

Controls how the navigation mask element resizes. Android defaults to transform-based resizing for performance; use "size" if transformed border radii look wrong and radius quality matters more. Valid values are "auto", "transform", and "size".

typedefaultrequired
MaskSizingMode"auto"No

Platform Notes

On Android, reveal uses a transform-based mask path by default to avoid masked-size animation issues. That keeps the API the same, but transformed masks can make large border radii look less natural. Use maskSizingMode: "size" to force width and height animation when border radius quality matters more than the Android optimization.

Reveal vs Zoom

Use Zoom when the matched element should float above the transition and the background content should scale behind it.

Use reveal when the destination content itself should grow out of the source and remain clipped by a navigation mask during the handoff.

Layout clipping caveat. If the source boundary lives inside a clipping layout such as a ScrollView, FlatList, or another constrained container, add escapeClipping to the boundary. That lets the animated payload render through the screen host during the transition while the boundary keeps its measured layout slot in place.