Skip to main content
Version 3.4 introduces powerful features for advanced animations, improved developer ergonomics, and better support for complex navigation scenarios.

New Features

Auto Snap Points with Intrinsic Sizing

Sheets now support snapPoints: ["auto"] for automatic content sizing. No need to hardcode dimensions:
<Transition.Modal
  snapPoints={["auto", 1]}
  screenStyleInterpolator={({ progress, layouts }) => ({
    content: {
      style: {
        transform: [{
          translateY: interpolate(progress, [0, 1, 2], [
            layouts.content?.height ?? 300,
            0,
            -100
          ]),
        }],
      },
    },
  })}
>
  {/* Content automatically measures its height */}
</Transition.Modal>
Access measured dimensions via layouts.content in your interpolator.

Boundary Components for Shared Elements

Explicit boundary components replace the deprecated sharedBoundTag prop. They’re clearer and more composable:
// Source boundary
<Transition.Boundary.Pressable
  id="hero"
  onPress={() => navigation.navigate('Details')}
>
  <Image {...} />
</Transition.Boundary.Pressable>

// Destination boundary
<Transition.Boundary.View id="hero">
  <Image {...} />
</Transition.Boundary.View>
Also works with Transition.Boundary.Target for registering animation targets.

Boundary Component Factory

Create custom boundary components wrapping your own components:
const CustomBoundary = Transition.createBoundaryComponent(MyComponent, {
  alreadyAnimated: false,
});

<CustomBoundary id="avatar">
  {/* Your component content */}
</CustomBoundary>
Animate shared elements to/from fullscreen with the new bounds().navigation.zoom() method:
const screenStyleInterpolator = ({ bounds }) => {
  "worklet";
  return bounds({ id: "hero" }).navigation.zoom({
    target: "fullscreen",
  });
};
Perfect for hero/detail transitions where an element expands to fill the screen. Instead of manually setting up Transition.MaskedView, use the new navigationMaskEnabled option:
<Transition.Stack
  navigationMaskEnabled
  screenStyleInterpolator={screenStyleInterpolator}
>
  {/* screens */}
</Transition.Stack>
Provides automatic masking for shared element reveal effects without extra components.

Ancestor Targeting in Gesture Hooks

Control which navigator level owns a gesture with ancestor targeting:
// Own the gesture on self
useScreenGesture("self", {
  gestureEnabled: true,
});

// Inherit from parent
useScreenGesture("parent", {
  gestureEnabled: true,
});

// Use root navigator's gesture
useScreenGesture("root", {
  gestureEnabled: true,
});

// Target specific ancestor by level
useScreenGesture({ ancestor: 2 }, {
  gestureEnabled: true,
});
Same options available for useScreenAnimation().

Velocity-Based Release Behavior

Fine-tune how gestures respond to release velocity:
<Transition.Stack
  gestureEnabled
  gestureReleaseVelocityScale={1.5}
  gestureReleaseVelocityMax={2000}
>
  {/* screens */}
</Transition.Stack>
  • gestureReleaseVelocityScale: Multiplier for release velocity (default: 1)
  • gestureReleaseVelocityMax: Cap for release velocity in pixels/second

Sheet Scroll Gesture Behavior

Replace expandViaScrollView boolean with explicit behavior control:
<Transition.Modal
  sheetScrollGestureBehavior="expand-and-collapse"
  // or
  sheetScrollGestureBehavior="collapse-only"
>
  {/* sheet content */}
</Transition.Modal>
  • "expand-and-collapse": Both expand and collapse work at scroll boundary
  • "collapse-only": Only collapse works; expand requires dead space at top

Surface Slot with Custom Component

Render custom surface layers with surfaceComponent:
const SurfaceInterpolator = ({ progress }) => {
  "worklet";
  return {
    content: { style: { opacity: 1 } },
    surface: {
      style: { backgroundColor: 'rgba(0,0,0,0.5)' },
      props: { pointerEvents: 'none' },
    },
  };
};

<Transition.Stack
  screenStyleInterpolator={SurfaceInterpolator}
  surfaceComponent={(props) => (
    <View {...props} style={[props.style, { backgroundColor: 'transparent' }]} />
  )}
>
  {/* screens */}
</Transition.Stack>

Deferred First Frames

Return "defer" from interpolators to delay animation until bounds snapshot is available:
const screenStyleInterpolator = ({ bounds }) => {
  "worklet";
  const snapshot = bounds.getSnapshot("hero");

  // Wait until source bounds are measured
  if (!snapshot) return "defer";

  return {
    content: {
      style: { opacity: interpolate(progress, [0, 1], [0, 1]) },
    },
  };
};
Ensures smooth animations when shared elements need measured dimensions.

Experimental Mount Animation

Opt-in animation on initial mount:
<Transition.Stack
  experimental_animateOnInitialMount
  screenStyleInterpolator={screenStyleInterpolator}
>
  {/* screens */}
</Transition.Stack>
Useful for entrance animations when the screen is first rendered.

Bounds Group Option

Organize bounds into groups for paged or detail flow layouts:
<Transition.Stack
  screenOptions={{
    boundsOptions: {
      group: "detail", // or "paged"
    },
  }}
>
  {/* screens */}
</Transition.Stack>
Enables advanced multi-screen shared element coordination.

Improvements

Slot-Based Return Format

All custom animations now use a cleaner, more modular slot-based return format:
return {
  content: { style: { ... } },
  backdrop: { style: { ... } },
  surface: { style: { ... }, props: { ... } },
  ["my-id"]: { style: { ... } },
};
Replaces the flat contentStyle/backdropStyle format (still supported but deprecated).

Deprecations

sharedBoundTag on Transition.View/Pressable

The sharedBoundTag prop is deprecated. Use Transition.Boundary.View and Transition.Boundary.Pressable instead:
// ❌ Deprecated
<Transition.View sharedBoundTag="avatar">
  <Image {...} />
</Transition.View>

// ✅ Use instead
<Transition.Boundary.View id="avatar">
  <Image {...} />
</Transition.Boundary.View>

Transition.MaskedView

Transition.MaskedView is deprecated. Use navigationMaskEnabled for new code:
// ❌ Deprecated
<Transition.MaskedView>
  <Transition.Stack>
    {/* screens */}
  </Transition.Stack>
</Transition.MaskedView>

// ✅ Use instead
<Transition.Stack navigationMaskEnabled>
  {/* screens */}
</Transition.Stack>
The old approach still works for legacy code, but new projects should migrate.

Flat Return Format (contentStyle/backdropStyle)

The flat contentStyle/backdropStyle return format is deprecated:
// ❌ Deprecated
return {
  contentStyle: { opacity: 1 },
  backdropStyle: { opacity: 0.5 },
};

// ✅ Use instead
return {
  content: { style: { opacity: 1 } },
  backdrop: { style: { opacity: 0.5 } },
};
The old format still works but is not recommended for new code.

expandViaScrollView Boolean

Replaced by sheetScrollGestureBehavior:
// ❌ Deprecated
expandViaScrollView={true}

// ✅ Use instead
sheetScrollGestureBehavior="expand-and-collapse"

Migration Path

Coming from v3.3? See the Migrating to 3.4 guide for step-by-step instructions.

Breaking Changes

None. Version 3.4 is fully backward compatible with 3.3. All deprecated APIs continue to work, but we recommend migrating to the new patterns for better code clarity and future compatibility.

Performance Notes

  • Auto snap points require additional layout measurements but are optimized for minimal overhead
  • Navigation zoom uses GPU-accelerated transforms for smooth fullscreen animations
  • Deferred frames prevent unnecessary redraws until bounds are ready
  • Ancestor targeting helps optimize gesture processing in complex hierarchies

Documentation Updates

All guides and examples have been updated to reflect v3.4 patterns. The documentation uses the slot-based format exclusively for new code.