Skip to main content
Creates a native stack navigator that extends @react-navigation/native-stack with custom transition support. Use this when you need native screen primitives with custom animations.

Function Signature

function createNativeStackNavigator<
  ParamList extends ParamListBase = ParamListBase,
  NavigatorID extends string | undefined = undefined
>(config?: StaticConfig): TypedNavigator<TypeBag, Config>

Type Parameters

ParamList
ParamListBase
default:"ParamListBase"
The parameter list for the navigator, defining route names and their parameters
NavigatorID
string | undefined
default:"undefined"
Optional unique identifier for the navigator instance

Parameters

config
StaticConfig
Optional static configuration for the navigator (rarely needed)

Return Value

TypedNavigator
TypedNavigator<TypeBag, Config>
Returns a typed navigator object containing:
  • Navigator: The navigator component
  • Screen: The screen component for defining routes
  • Group: Component for grouping screens with shared options

Import

import { createNativeStackNavigator } from "react-native-screen-transitions/native-stack";

Usage

Basic Setup

import { createNativeStackNavigator } from "react-native-screen-transitions/native-stack";
import Transition from "react-native-screen-transitions";

const Stack = createNativeStackNavigator();

function App() {
  return (
    <Stack.Navigator>
      <Stack.Screen name="Home" component={HomeScreen} />
      <Stack.Screen
        name="Detail"
        component={DetailScreen}
        options={{
          enableTransitions: true,
          ...Transition.Presets.SlideFromBottom(),
        }}
      />
    </Stack.Navigator>
  );
}
Important: You must set enableTransitions: true on screens where you want custom transitions. Without this flag, the screen will use native platform defaults.

With TypeScript

import { createNativeStackNavigator } from "react-native-screen-transitions/native-stack";
import type { NativeStackNavigationProp } from "react-native-screen-transitions/native-stack";

type RootStackParamList = {
  Home: undefined;
  Detail: { id: string };
  Profile: { userId: string };
};

const Stack = createNativeStackNavigator<RootStackParamList>();

// Type-safe navigation prop
type HomeScreenProps = {
  navigation: NativeStackNavigationProp<RootStackParamList, 'Home'>;
};

function HomeScreen({ navigation }: HomeScreenProps) {
  return (
    <Button
      title="Go to Detail"
      onPress={() => navigation.navigate('Detail', { id: '123' })}
    />
  );
}

Native Headers

The Native Stack supports all standard @react-navigation/native-stack header options:
<Stack.Screen
  name="Detail"
  component={DetailScreen}
  options={{
    enableTransitions: true,
    title: "Detail Screen",
    headerShown: true,
    headerStyle: { backgroundColor: '#f4511e' },
    headerTintColor: '#fff',
    headerTitleStyle: { fontWeight: 'bold' },
    ...Transition.Presets.SlideFromBottom(),
  }}
/>

Features

Custom Animations

When enableTransitions: true is set, you get full animation control:
<Stack.Screen
  name="Detail"
  options={{
    enableTransitions: true,
    screenStyleInterpolator: ({ progress, layouts: { screen } }) => {
      "worklet";
      return {
        contentStyle: {
          opacity: interpolate(progress, [0, 1, 2], [0, 1, 0]),
          transform: [{
            translateY: interpolate(
              progress,
              [0, 1],
              [screen.height, 0]
            ),
          }],
        },
      };
    },
  }}
/>

Platform Defaults

Without enableTransitions, screens use native platform transitions:
<Stack.Screen
  name="Settings"
  component={SettingsScreen}
  // No enableTransitions = native platform behavior
  options={{
    title: "Settings",
  }}
/>

Mixed Approach

You can mix custom and native transitions in the same stack:
<Stack.Navigator>
  {/* Native transition */}
  <Stack.Screen name="Home" component={HomeScreen} />
  
  {/* Custom transition */}
  <Stack.Screen
    name="Modal"
    component={ModalScreen}
    options={{
      enableTransitions: true,
      ...Transition.Presets.SlideFromBottom(),
    }}
  />
  
  {/* Native transition */}
  <Stack.Screen name="Settings" component={SettingsScreen} />
</Stack.Navigator>

When to Use

Use Native Stack When

  • You need native screen headers
  • Mixing custom and platform transitions
  • Gradual migration from native-stack
  • Platform-specific features required

Use Blank Stack Instead

  • You want custom animations everywhere
  • You need maximum control
  • Building from scratch
  • No need for native headers

Caveats

The Native Stack uses transparent modal presentation to intercept transitions. This has trade-offs:
  • Delayed touch events: Exiting screens may have briefly delayed touch response
  • beforeRemove listeners: Relies on navigation lifecycle events
  • Rapid navigation: Some edge cases with very fast navigation sequences
For most apps, Blank Stack avoids these issues entirely.

Architecture

  • Base: Extends @react-navigation/native-stack
  • Intercept Method: Uses transparent modal presentation to intercept transitions
  • Animation Engine: Reanimated worklets on UI thread (when enableTransitions: true)
  • Headers: Native platform headers fully supported

Comparison with Blank Stack

FeatureNative StackBlank Stack
Custom animations✓ (with flag)✓ (always)
Platform defaults
Native headers
Touch responsivenessGoodExcellent
Setup complexityMediumSimple
PerformanceExcellentExcellent

Exported Types

import type {
  NativeStackNavigationOptions,
  NativeStackNavigationProp,
  NativeStackScreenProps,
  NativeStackNavigatorProps,
  NativeStackNavigationEventMap,
  NativeStackOverlayProps,
  NativeStackOptionsArgs,
  NativeStackHeaderProps,
  NativeStackHeaderLeftProps,
  NativeStackHeaderRightProps,
} from "react-native-screen-transitions/native-stack";

Migration from @react-navigation/native-stack

// Before
import { createNativeStackNavigator } from '@react-navigation/native-stack';

// After
import { createNativeStackNavigator } from 'react-native-screen-transitions/native-stack';

// Then add custom transitions where needed
<Stack.Screen
  name="Detail"
  options={{
    enableTransitions: true,  // Add this
    ...Transition.Presets.SlideFromBottom(),  // Add this
  }}
/>