Your First Transition
The simplest way to get started is using a preset animation with a Stack navigator:
import { Transition } from 'react-native-screen-transitions';
import { View, Text, Pressable } from 'react-native';
import { useNavigation } from '@react-navigation/native';
export default function HomeScreen() {
const navigation = useNavigation();
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text style={{ fontSize: 24, marginBottom: 20 }}>Home</Text>
<Pressable
onPress={() => navigation.navigate('Details')}
style={{ padding: 10, backgroundColor: '#007AFF', borderRadius: 8 }}
>
<Text style={{ color: 'white' }}>Go to Details</Text>
</Pressable>
</View>
);
}
export function RootStack() {
return (
<Transition.Stack
screenOptions={{
headerShown: false,
animationEnabled: true,
transitionSpec: 'default',
}}
>
<Transition.Screen name="Home" component={HomeScreen} />
<Transition.Screen name="Details" component={DetailsScreen} />
</Transition.Stack>
);
}
Using Preset Animations
The library includes several built-in animations. Specify them with transitionSpec:
<Transition.Stack
screenOptions={{
transitionSpec: 'slide', // 'default', 'slide', 'fade', 'zoom'
}}
>
{/* screens */}
</Transition.Stack>
Custom Animations with Slots
For more control, define a custom screenStyleInterpolator using the slot-based return format:
import { interpolate } from 'react-native-reanimated';
const customInterpolator = ({ progress }) => {
"worklet";
return {
content: {
style: {
opacity: interpolate(progress, [0, 1], [0, 1]),
transform: [
{
translateY: interpolate(progress, [0, 1], [100, 0]),
},
],
},
},
backdrop: {
style: {
opacity: interpolate(progress, [0, 1], [0, 0.5]),
},
},
};
};
<Transition.Stack screenStyleInterpolator={customInterpolator}>
{/* screens */}
</Transition.Stack>
Adding Gestures
Enable interactive dismissal with gesture control:
<Transition.Stack
screenStyleInterpolator={customInterpolator}
gestureEnabled
gestureDirection="vertical"
gestureActivationArea={{ top: 0, bottom: 0, left: 0, right: 0 }}
>
{/* screens */}
</Transition.Stack>
Users can now drag the screen vertically to dismiss it.
Modal Overlay
For modal-style overlays, use Transition.Modal:
<Transition.Modal
name="Modal"
screenStyleInterpolator={customInterpolator}
gestureEnabled
gestureDirection="vertical"
>
{/* modal content */}
</Transition.Modal>
Using Snap Points (Sheets)
For bottom sheets with snap points, define positions where the sheet can rest:
const sheetInterpolator = ({ progress, layouts }) => {
"worklet";
const height = layouts.content?.height ?? 300;
return {
content: {
style: {
transform: [
{
translateY: interpolate(progress, [0, 1, 2], [height, 0, -100]),
},
],
},
},
};
};
<Transition.Modal
screenStyleInterpolator={sheetInterpolator}
snapPoints={[0.4, 1]}
gestureEnabled
sheetScrollGestureBehavior="expand-and-collapse"
>
{/* sheet content */}
</Transition.Modal>
Auto Snap Points
For responsive sheets that size to content, use "auto":
<Transition.Modal
screenStyleInterpolator={sheetInterpolator}
snapPoints={["auto", 1]}
gestureEnabled
>
{/* content automatically sizes based on actual height */}
</Transition.Modal>
In your interpolator, access the measured height with layouts.content.height:
const sheetInterpolator = ({ progress, layouts }) => {
"worklet";
const contentHeight = layouts.content?.height ?? 300;
return {
content: {
style: {
transform: [
{
translateY: interpolate(
progress,
[0, 1, 2],
[contentHeight, 0, -100]
),
},
],
},
},
};
};
Shared Element Animation
Link elements between screens with Transition.Boundary components:
// Home screen
<Transition.Boundary.Pressable
id="avatar"
onPress={() => navigation.navigate('Details')}
>
<Image source={{ uri: 'https://...' }} style={{ width: 80, height: 80 }} />
</Transition.Boundary.Pressable>
// Details screen
<Transition.Boundary.View id="avatar">
<Image source={{ uri: 'https://...' }} style={{ width: 200, height: 200 }} />
</Transition.Boundary.View>
Then animate the bounds in your interpolator:
const screenStyleInterpolator = ({ bounds }) => {
"worklet";
const avatarBounds = bounds({ id: 'avatar' });
return {
content: {
style: {
opacity: interpolate(progress, [0, 1], [0, 1]),
},
},
};
};
Next Steps
Now that you understand the basics:
Start simple with presets, then customize when you need more control. The slot-based return format scales from basic to advanced animations.