Skip to main content

Create A Blank Stack Navigator

Start with blank stack and a normal NavigationContainer:
import { NavigationContainer } from "@react-navigation/native";
import Transition from "react-native-screen-transitions";
import { createBlankStackNavigator } from "react-native-screen-transitions/blank-stack";
import { View, Text, TouchableOpacity } from "react-native";

const Stack = createBlankStackNavigator();

function HomeScreen({ navigation }) {
  return (
    <View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
      <TouchableOpacity onPress={() => navigation.navigate("Detail")}>
        <Text>Open Detail</Text>
      </TouchableOpacity>
    </View>
  );
}

function DetailScreen() {
  return (
    <View style={{ flex: 1, backgroundColor: "#fff", justifyContent: "center" }}>
      <Text>Detail Screen</Text>
    </View>
  );
}

export default function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator>
        <Stack.Screen name="Home" component={HomeScreen} />
        <Stack.Screen name="Detail" component={DetailScreen} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}
That gives you a working stack. Blank stack does not impose a built-in transition, so the next step is to add one.

Add A Preset Animation

Use a preset in screen options:
<Stack.Screen
  name="Detail"
  component={DetailScreen}
  options={{
    ...Transition.Presets.SlideFromBottom(),
  }}
/>

Presets That Exist On Main

These preset names still exist on the current source:
PresetBehaviorBest For
SlideFromTop()Slides in from the topInverted modal flows
SlideFromBottom()Slides up from the bottomModal dialogs and sheets
ZoomIn()Scale + fadeSimple focus transitions
DraggableCard()Free-form drag dismissalGesture-heavy cards
ElasticCard()Elastic card motionPlayful full-screen cards
SharedIGImage({ sharedBoundTag })Instagram-style shared image presetImage transitions
SharedAppleMusic({ sharedBoundTag })Apple Music-style presetAlbum-to-player flows
SharedXImage({ sharedBoundTag })X-style shared image presetMedia detail flows

Enable Gestures

Swipe-to-dismiss is still configured through screen options:
options={{
  ...Transition.Presets.SlideFromBottom(),
  gestureEnabled: true,
  gestureDirection: "vertical",
}}

Shared Preset Example

The shared presets require sharedBoundTag:
<Stack.Screen
  name="Photo"
  component={PhotoScreen}
  options={{
    ...Transition.Presets.SharedIGImage({
      sharedBoundTag: "photo",
    }),
  }}
/>
Match that tag on the source and destination:
<Transition.Pressable sharedBoundTag="photo" onPress={openPhoto}>
  <Image source={photo} />
</Transition.Pressable>

<Transition.View sharedBoundTag="photo">
  <Image source={photo} />
</Transition.View>

What’s Next