Components

Stack Types

Choose between blank stack and native-stack adapter integration.

Blank Stack

Blank stack is a highly customizable navigator for complex animation and gesture systems. It is intentionally kept blank: the navigator gives you the transition runtime, but leaves the visual language, headers, chrome, and design-system decisions to your app.

Use it when your app should define itself through custom motion instead of adapting platform navigation defaults.

TSX

1const Stack = createBlankStackNavigator();
2
3<Stack.Navigator>
4 <Stack.Screen name="Home" component={HomeScreen} />
5 <Stack.Screen
6 name="Detail"
7 component={DetailScreen}
8 options={{
9 ...Transition.Presets.SlideFromBottom(),
10 gestureEnabled: true,
11 }}
12 />
13</Stack.Navigator>

Use blank stack when you want the full transition system without native-stack constraints:

  • custom screen interpolators
  • gestures
  • snap sheets
  • bounds transitions
  • navigation zoom
  • overlays

Embedded and Independent Flows

Blank stack covers embedded navigation flows through independent mode.

It supports first-class navigator props:

  • independent
  • nativeScreens

TSX

1const Stack = createBlankStackNavigator();
2
3<Stack.Navigator independent nativeScreens={false}>
4 {/* embedded flow */}
5</Stack.Navigator>

independent creates an isolated navigation tree.

nativeScreens={false} renders with regular views instead of react-native-screens, which is often the right choice for embedded UI.

The static API supports the same idea:

TSX

1const Stack = createBlankStackNavigator({
2 independent: true,
3 nativeScreens: false,
4 screens: {
5 Home: HomeScreen,
6 Detail: DetailScreen,
7 },
8});

Blank stack is now the preferred path for new embedded and independent flows.

Native Stack

Use the adapter when you want @react-navigation/native-stack behavior while opting into the transition system.

TSX

1const NativeStack = createNativeStackNavigator();
2const Stack = withScreenTransitions(NativeStack);
3
4<Stack.Navigator>
5 <Stack.Screen
6 name="Detail"
7 component={DetailScreen}
8 options={{
9 enableTransitions: true,
10 ...Transition.Presets.SlideFromBottom(),
11 }}
12 />
13</Stack.Navigator>

Custom transitions are active only on screens with enableTransitions: true.

This is an integration path, not the default recommendation for custom motion work.

Under the hood, the transitioned native-stack screen is switched into a transparent modal-style presentation, native animation is disabled, and the library drives the transition visuals with Reanimated on top of that container.

That makes native stack useful when you already depend on native-stack behavior, native headers, or existing native-stack screen primitives and only want to opt a specific screen or flow into a custom transition.

If you want the most control over interpolators, gestures, snap sheets, overlays, and bounds-driven motion, blank stack is the better fit.

Shared Screen Options

Blank stack and the native-stack adapter both use screen options.

Common options include:

  • screenStyleInterpolator
  • transitionSpec
  • gestureEnabled
  • gestureDirection
  • gestureTracking
  • snapPoints
  • navigationMaskEnabled
  • overlay
  • overlayShown
  • inactiveBehavior

The native-stack adapter accepts native-stack options alongside transition options, but transition behavior only participates when enableTransitions is turned on.

For blank-stack route retention, see Inactive Behavior.

Overlays and Stack Scope

Overlays are stack-relative.

If a screen defines an overlay, it floats through the rest of that stack until a higher owner takes over or the stack unwinds.

Blank stack supports overlays directly and is the default place to start. Native stack supports overlays on transitioned screens.

Which One to Pick

  • blank stack: the default for nearly everything, including embedded and independent flows
  • native-stack adapter: when you need @react-navigation/native-stack integration and can opt into enableTransitions