Guides

Expo Router

Create a v3 blank stack layout for Expo Router with createBlankStackNavigator and withLayoutContext.

Overview

The stable v3 Expo Router integration supports Expo SDK 55 and earlier. It wraps createBlankStackNavigator() with Expo Router's withLayoutContext(), using the React Navigation-backed navigator internals available in those SDKs.

Expo SDK 55 is the final SDK supported by this v3 integration. Expo Router forked the navigation packages it builds upon in SDK 56. For Expo SDK 56 or later, use the separate v4 alpha Expo Router integration.

The SDK 56 boundary applies to Expo Router, not to Expo projects generally. An Expo app using React Navigation directly can continue to use v3. See Expo's SDK 55 to 56 migration guide for details about the upstream import and runtime changes.

If you want a complete reference app before integrating this into an existing project, use the v3 Expo Router starter. It pins Expo SDK 55, the final Expo Router environment supported by the v3 integration and the version used by the v3 e2e app.

Blank Stack Layout

This is the v3 integration pattern used by the e2e app and starter:

TSX

1// layouts/blank-stack.tsx
2import "react-native-reanimated";
3import type {
4 ParamListBase,
5 StackNavigationState,
6} from "@react-navigation/native";
7import { withLayoutContext } from "expo-router";
8import type { ComponentProps } from "react";
9import {
10 type BlankStackNavigationEventMap,
11 type BlankStackNavigationOptions,
12 createBlankStackNavigator,
13} from "react-native-screen-transitions/blank-stack";
14
15const { Navigator } = createBlankStackNavigator();
16
17function BlankStackNavigator(props: ComponentProps<typeof Navigator>) {
18 return <Navigator {...props} />;
19}
20
21export const BlankStack = withLayoutContext<
22 BlankStackNavigationOptions,
23 typeof BlankStackNavigator,
24 StackNavigationState<ParamListBase>,
25 BlankStackNavigationEventMap
26>(BlankStackNavigator);

The local wrapper provides a stable TypeScript boundary for withLayoutContext() while forwarding navigator props unchanged. Native screens remain enabled by default.

Using It In Route Layouts

TSX

1// app/gestures/_layout.tsx
2import Transition from "react-native-screen-transitions";
3import { BlankStack } from "@/layouts/blank-stack";
4
5export default function GesturesLayout() {
6 return (
7 <BlankStack>
8 <BlankStack.Screen name="index" />
9 <BlankStack.Screen
10 name="sheet"
11 options={{
12 ...Transition.Presets.SlideFromBottom(),
13 }}
14 />
15 </BlankStack>
16 );
17}

router.push(), router.replace(), and router.back() still work normally. The transition behavior comes from the options you put on BlankStack.Screen.

Bounds And Router Navigation

TSX

1import { router } from "expo-router";
2import Transition from "react-native-screen-transitions";
3
4<Transition.Boundary
5 id="hero"
6 onPress={() => router.push("/detail")}
7>
8 <Card />
9</Transition.Boundary>

The destination can use a matching passive Transition.Boundary, Transition.Boundary.Target, navigationMaskEnabled, and screenStyleInterpolator the same way it would outside Expo Router.

Embedded Flows

TSX

1<BlankStack independent nativeScreens={false}>
2 <BlankStack.Screen name="index" />
3</BlankStack>

Use independent only when you want an isolated navigation tree, not for normal route layouts.