Skip to main content

Overview

Transition components provide the foundation for animated navigation. They handle animation orchestration, gesture coordination, and bounds tracking.

Core Navigator Components

Transition.Stack

Navigates between screens with customizable animations:
<Transition.Stack
  screenOptions={{
    headerShown: false,
    animationEnabled: true,
  }}
  screenStyleInterpolator={({ progress }) => ({
    content: {
      style: {
        opacity: interpolate(progress, [0, 1], [0, 1]),
      },
    },
  })}
  gestureEnabled
  gestureDirection="vertical"
>
  <Transition.Screen name="Home" component={HomeScreen} />
  <Transition.Screen name="Details" component={DetailsScreen} />
</Transition.Stack>
Properties:
  • screenStyleInterpolator: Animation function
  • screenOptions: Navigation options (headerShown, animationEnabled, etc.)
  • gestureEnabled: Enable/disable gestures
  • gestureDirection: “horizontal” or “vertical”
  • All gesture options (velocity scale, snap behavior, etc.)

Transition.Modal

Presents screens as modal overlays with snap points:
<Transition.Modal
  name="DetailsModal"
  component={DetailsScreen}
  options={{
    snapPoints: [0.5, 1],
    gestureEnabled: true,
    screenStyleInterpolator: modalInterpolator,
  }}
/>
Unique Properties:
  • snapPoints: Array of positions (0–1 or “auto”)
  • sheetScrollGestureBehavior: “expand-and-collapse” or “collapse-only”
  • navigationMaskEnabled: Enable built-in masking

Transition.Screen

Individual screen definition:
<Transition.Screen
  name="Details"
  component={DetailsScreen}
  options={{
    title: "Details",
  }}
/>

Boundary Components

Transition.Boundary.View

Marks a view as a shared element source or destination:
<Transition.Boundary.View
  id="avatar"
  style={{ width: 100, height: 100, borderRadius: 50 }}
>
  <Image source={avatar} style={{ flex: 1, borderRadius: 50 }} />
</Transition.Boundary.View>
Props:
  • id: Unique identifier for this boundary
  • style: Standard View styles
  • children: Content

Transition.Boundary.Pressable

A pressable boundary that captures source bounds on press:
<Transition.Boundary.Pressable
  id="hero-image"
  onPress={() => navigation.navigate('Details')}
>
  <Image source={image} style={{ width: 200, height: 300 }} />
</Transition.Boundary.Pressable>
Props:
  • id: Unique identifier
  • onPress: Called when pressed
  • disabled: Disable pressable behavior
  • Standard Pressable props (onLongPress, delayLongPress, etc.)

Transition.Boundary.Target

Register animation targets without rendering extra elements:
<Transition.Boundary.Target id="measurement-point">
  <CustomComponent />
</Transition.Boundary.Target>

Animated View Components

Transition.View

An animated view with optional styleId for per-element animation:
<Transition.View
  styleId="title"
  style={{ fontSize: 24, fontWeight: 'bold' }}
>
  <Text>Animated Title</Text>
</Transition.View>
Props:
  • styleId: Unique ID for animation targeting in interpolators
  • Standard View props
The styleId allows the interpolator to target this view specifically:
return {
  "title": {
    style: { fontSize: interpolate(progress, [0, 1], [18, 24]) },
  },
};

Transition.Pressable

Pressable with animation support:
<Transition.Pressable
  styleId="button"
  onPress={handlePress}
>
  <Text>Press me</Text>
</Transition.Pressable>
Same as Transition.View but with Pressable functionality.

Transition.ScrollView

ScrollView with gesture coordination:
<Transition.ScrollView
  scrollEventThrottle={16}
  showsVerticalScrollIndicator={false}
>
  <Content />
</Transition.ScrollView>
Automatically coordinates scroll gestures with navigator gestures at boundaries.

Transition.FlatList

FlatList with gesture coordination:
<Transition.FlatList
  data={items}
  renderItem={({ item }) => <ItemComponent {...item} />}
  keyExtractor={(item) => item.id}
  scrollEventThrottle={16}
/>

Deprecated Components

Transition.MaskedView

Deprecated. Use navigationMaskEnabled instead:
// ❌ Deprecated
<Transition.MaskedView>
  <Transition.Stack>
    {/* screens */}
  </Transition.Stack>
</Transition.MaskedView>

// ✅ New approach
<Transition.Stack navigationMaskEnabled>
  {/* screens */}
</Transition.Stack>

Helper Functions

Transition.createBoundaryComponent

Create custom boundary components wrapping your own elements:
import { Transition } from 'react-native-screen-transitions';

const CustomCard = ({ title, onPress, children, ...props }) => (
  <TouchableOpacity onPress={onPress} {...props}>
    <Text>{title}</Text>
    {children}
  </TouchableOpacity>
);

export const SharedCard = Transition.createBoundaryComponent(CustomCard, {
  alreadyAnimated: false,
});

// Usage
<SharedCard
  id="card-1"
  title="Card Title"
  onPress={() => navigation.navigate('Details')}
>
  {children}
</SharedCard>
Options:
  • alreadyAnimated?: boolean - Set true if component already applies animations

Transition.createTransitionAwareComponent

Wrap components to make them aware of transition state:
import { Transition } from 'react-native-screen-transitions';

const CustomScrollable = ({ children, ...props }) => (
  <ScrollView {...props}>{children}</ScrollView>
);

export const TransitionScrollView = Transition.createTransitionAwareComponent(
  CustomScrollable,
  {
    isScrollable: true,
    alreadyAnimated: false,
  }
);
Options:
  • isScrollable?: boolean - Component handles scroll gestures
  • alreadyAnimated?: boolean - Component applies animations internally

Screen Components Table

ComponentPurposeKey Features
Transition.StackStack navigatorCustomizable animations, gestures
Transition.ModalModal navigatorSnap points, overlays
Transition.ScreenScreen definitionBasic screen wrapper
Transition.Boundary.ViewShared elementSource/destination boundaries
Transition.Boundary.PressableInteractive boundaryCaptures bounds on press
Transition.Boundary.TargetTarget registrationLightweight bounds marker
Transition.ViewAnimated viewPer-element animation via styleId
Transition.PressableAnimated pressablePressable with animations
Transition.ScrollViewCoordinated scrollGesture coordination
Transition.FlatListCoordinated listGesture coordination

Props Reference

Common Navigator Props

interface CommonNavigatorProps {
  // Animation
  screenStyleInterpolator?: ScreenStyleInterpolator;
  gestureEnabled?: boolean;
  gestureDirection?: "horizontal" | "vertical";

  // Gesture options
  gestureActivationArea?: ActivationArea;
  gestureResponseDistance?: ResponseDistance;
  gestureVelocityImpact?: number;
  gestureDrivesProgress?: boolean;
  snapVelocityImpact?: number;
  gestureSnapLocked?: boolean;
  gestureReleaseVelocityScale?: number;
  gestureReleaseVelocityMax?: number;

  // Backdrop
  backdropBehavior?: "static" | "interactive";
  backdropComponent?: React.ComponentType;

  // Sheet-specific
  snapPoints?: (number | "auto")[];
  sheetScrollGestureBehavior?: "expand-and-collapse" | "collapse-only";

  // Masking
  navigationMaskEnabled?: boolean;

  // Custom surface
  surfaceComponent?: React.ComponentType;

  // Experimental
  experimental_animateOnInitialMount?: boolean;
}

Styling Props

Boundary Component Styling

<Transition.Boundary.View
  id="avatar"
  style={{
    width: 100,
    height: 100,
    borderRadius: 50,
    backgroundColor: "#FF6B6B",
  }}
>
  {/* content */}
</Transition.Boundary.View>

Animated Styling via Interpolator

const interpolator = ({ progress }) => ({
  content: {
    style: {
      opacity: interpolate(progress, [0, 1], [0, 1]),
      transform: [{
        translateY: interpolate(progress, [0, 1], [100, 0]),
      }],
    },
  },
});

TypeScript Support

All components are fully typed:
import { Transition } from 'react-native-screen-transitions';
import type {
  ScreenStyleInterpolator,
  NavigationOptions,
  BoundaryProps,
} from 'react-native-screen-transitions';

const myInterpolator: ScreenStyleInterpolator = ({ progress, bounds }) => {
  "worklet";
  return {
    content: { style: { opacity: 1 } },
  };
};

<Transition.Stack screenStyleInterpolator={myInterpolator}>
  {/* screens */}
</Transition.Stack>

Next Steps