Stack Navigator — a React Navigation library component for managing mobile app screens using the stack principle (LIFO). Each new screen is placed on top of the previous one, and the «Back» button removes the top screen and returns the user to the previous one. Read more about navigation architecture in the official React Navigation documentation.
Key Takeaways
Stack Navigator is one of the basic navigators of the React Navigation library that implements the stack screen model. It provides the navigation mobile users are familiar with: opening a new screen is accompanied by a slide-right animation, and the «Back» button or swipe gesture returns to the previous screen. Stack Navigator supports iOS and Android, using native platform components for maximum performance.
React Navigation is the most popular navigation library for React Native, installed in 85% of projects (according to npm data, 2026). Stack Navigator is part of its core and is available in two implementations: createNativeStackNavigator (native, recommended) and createStackNavigator (JavaScript, for complex custom animations). The native version appeared in React Navigation v5 and became the standard in v6+.
The main advantage of Stack Navigator is the natural behavior familiar to iOS and Android users. On iOS, the stack is visually represented by UINavigationController, on Android — by FragmentManager with slide animation. The developer does not need to implement stack logic manually — the navigator manages screen states, back stack, and animations automatically.
Stack navigation is based on the LIFO (Last In, First Out) principle. When a user opens a new screen, the navigator places it on top of the stack. When «Back» is pressed, the top screen is removed and the user sees the previous one. The stack can contain any number of screens — the only limitation is device memory.
Each screen in the stack preserves its state. When returning to a previous screen, its state is restored automatically. This distinguishes a stack from other navigation types (Tab, Drawer), where screens may be recreated. React Navigation manages state through its own navigation context mechanism.
| Action | Result | Example |
|---|---|---|
| navigate | Places a screen on top of the stack | navigation.navigate('Profile') |
| goBack | Removes the top screen from the stack | navigation.goBack() |
| push | Forcefully adds a new screen | navigation.push('Profile') |
| popToTop | Returns to the root screen | navigation.popToTop() |
| reset | Replaces the entire stack with a new set | navigation.reset({ index: 0, routes: [...] }) |
On iOS, Stack Navigator supports a swipe-from-left-edge gesture to go back — this is standard iOS behavior that users expect. On Android, the gesture is disabled by default, but can be enabled via the gestureEnabled option. In Native Stack, the gesture works natively without JavaScript-thread delays.
React Navigation offers two types of Stack Navigator: Native Stack (createNativeStackNavigator) and JS Stack (createStackNavigator). The main difference is where the animation executes. Native Stack uses native animation drivers from iOS and Android, whereas JS Stack runs through the React Native JavaScript thread. The choice between them depends on performance and customization requirements.
Native Stack is recommended for most projects. It provides smooth 60 FPS animations without blocking the JS thread, supports the system swipe-back gesture on iOS, and uses native transitions — slide on iOS, fade on Android. However, Native Stack is limited in animation customization: only a predefined set of transitions is available.
JS Stack gives full control over animations via cardStyleInterpolator. The developer can create any animation: scaling, rotation, parallax, custom curves. The downside is that animations run in the JS thread, which can cause frame drops on weak devices with complex transitions. For 70% of projects, Native Stack is more than sufficient.
// Native Stack — recommended implementation
import { createNativeStackNavigator } from '@react-navigation/native-stack';
type RootStackParamList = {
Home: undefined;
Profile: { userId: string; name: string };
Settings: undefined;
};
const Stack = createNativeStackNavigator<RootStackParamList>();
function AppNavigator() {
return (
<Stack.Navigator screenOptions={{ headerShown: true }}>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Profile" component={ProfileScreen} />
<Stack.Screen name="Settings" component={SettingsScreen} />
</Stack.Navigator>
);
}To get started with Stack Navigator, you need to install React Navigation and its dependencies. The minimal set includes @react-navigation/native, @react-navigation/native-stack, and react-native-screens. After installation, the app is wrapped in NavigationContainer — a context that provides navigation state to all child components.
# Installing React Navigation dependencies
npm install @react-navigation/native @react-navigation/native-stack
npm install react-native-screens react-native-safe-area-context
# For iOS — install pod
cd ios && pod install && cd ..After installation, Stack.Navigator is created with specific screens defined in RootStackParamList. Each screen is linked to a React component via the component prop. The navigator can be root-level or nested inside another navigator (Tab, Drawer). For configuration, screenOptions are used — either common for all screens or individual for each.
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
type RootStackParamList = {
Home: undefined;
Details: { itemId: number; title: string };
};
const Stack = createNativeStackNavigator<RootStackParamList>();
export default function App() {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="Home"
screenOptions={{
headerStyle: { backgroundColor: '#6200ee' },
headerTintColor: '#fff',
gestureEnabled: true,
}}>
<Stack.Screen name="Home" component={HomeScreen}
options={{ title: 'Home' }} />
<Stack.Screen name="Details" component={DetailsScreen}
options={({ route }) => ({ title: route.params.title })} />
</Stack.Navigator>
</NavigationContainer>
);
}Stack Navigator provides many options for customizing appearance and behavior. The main parameters are set via screenOptions at the Navigator level or options at the Screen level. The developer can configure the header, transition animation, swipe gesture, card style, and background dimming. The flexibility of settings allows adapting navigation to the app's design system.
| Option | Type | Description |
|---|---|---|
| headerShown | boolean | Show or hide the screen header |
| headerStyle | object | Header bar style (backgroundColor, elevation) |
| headerBackTitle | string | «Back» button text (iOS) |
| gestureEnabled | boolean | Enable swipe-back gesture |
| animation | string | Animation type: slide_from_right, fade, none |
| contentStyle | object | Inner screen area style |
For JS Stack, cardStyleInterpolator allows creating arbitrary transition animations between screens. This is a powerful tool for implementing unique visual effects: scaling, rotation, parallax, horizontal flip. The function receives current animation progress values (current, next) and returns styles for the elements being animated.
Stack Navigator supports full typing via TypeScript. To do this, RootStackParamList is defined — an object type where keys are screen names and values are parameter types. After typing, navigation.navigate and route.params get autocompletion and type checking. This eliminates parameter-passing errors at compile time.
type RootStackParamList = {
Home: undefined;
Product: { id: string; category: string };
Checkout: { items: CartItem[]; total: number };
};
// Typed screen
type ProductScreenProps = NativeStackScreenProps<RootStackParamList, 'Product'>;
function ProductScreen({ navigation, route }: ProductScreenProps) {
const { id, category } = route.params;
return (
<View>
<Text>Product {id} — {category}</Text>
<Button title="Add to cart"
onPress={() => navigation.navigate('Checkout', {
items: [{ id, quantity: 1 }],
total: 99.99,
})} />
</View>
);
}Stack Navigator supports screen grouping and modal windows. Groups (Screen Group) allow applying common settings to multiple screens without duplication. Modal windows are implemented via stack presentation: 'modal' — the screen opens from the bottom with background dimming, like a system modal on iOS. This option is only available in Native Stack.
For complex navigation, Stack Navigator can be nested inside a Tab Navigator or Drawer Navigator. For example, the «Home» tab has its own stack of screens, and the «Profile» tab has its own. This composition of navigators is the standard approach for production applications. Each stack is isolated: the back stack within a tab does not affect other tabs.
// Nested stack in Tab Navigator
const HomeStack = createNativeStackNavigator<HomeStackParamList>();
function HomeStackScreen() {
return (
<HomeStack.Navigator>
<HomeStack.Screen name="Feed" component={FeedScreen} />
<HomeStack.Screen name="PostDetail" component={PostDetailScreen}
options={{ presentation: 'modal' }} />
</HomeStack.Navigator>
);
}
// Screen groups with shared options
<Stack.Navigator>
<Stack.Group screenOptions={{ headerShown: true }}>
<Stack.Screen name="Main" component={MainScreen} />
<Stack.Screen name="About" component={AboutScreen} />
</Stack.Group>
<Stack.Screen name="Auth" component={AuthScreen}
options={{ presentation: 'modal', headerShown: false }} />
</Stack.Navigator>Frequently Asked Questions
navigate first looks for an existing screen with that name in the stack and navigates to it if found. push always adds a new screen to the top of the stack, even if one already exists. push is useful when you need to open the same screen with different data (e.g., a user profile).
Parameters are passed as the second argument of the navigate method: navigation.navigate('Profile', { userId: '123', name: 'John' }). On the receiving screen, parameters are available via route.params. Parameter types are defined in RootStackParamList for TypeScript autocompletion.
Stack Navigator is suitable for linear navigation (screen → details → editing). Tab Navigator is for parallel sections of the app (Home, Search, Profile). In production projects, they are combined: Tab Navigator contains several Stack Navigators for each tab.
By default, Stack Navigator adds a «Back» button in the header for all screens except the root one. On iOS, the swipe-from-left-edge gesture also works. The navigation.goBack() method removes the current screen from the stack and returns the user to the previous one.
Native Stack provides predefined animations: slide_from_right, fade, none. For full customization, JS Stack is used with cardStyleInterpolator — a function that returns card styles on each animation frame. This allows creating any transitions: scaling, parallax, 3D rotation.
Summary
We will develop a mobile application turnkey
IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.
Read also