Navigation
Unlike web development, where the browser itself provides URLs and back/forward history, React
Native has no built-in navigation system whatsoever. Moving between screens —
a list screen to a detail screen, a login screen to a home screen — is entirely handled by a
separate, community-maintained package family: @react-navigation. It's the
de facto standard used by the vast majority of React Native apps, and it's what this page
focuses on.
Installing React Navigation
React Navigation is split into a small core library plus one or more "navigator" packages, installed separately depending on which navigation pattern you need:
// Core library, required for every setup
npm install @react-navigation/native
// A specific navigator type — stack navigation is the most common starting point
npm install @react-navigation/native-stack
// Plus a few native dependencies React Navigation itself relies on
npm install react-native-screens react-native-safe-area-context
The Stack Navigator
The Stack Navigator is the most common navigation pattern: screens stack on top of one another, like a deck of cards. Navigating "forward" pushes a new screen on top; the system back button (Android) or edge-swipe gesture (iOS) pops it back off, returning to the previous screen — all handled automatically once it's set up.
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import HomeScreen from './screens/HomeScreen';
import DetailsScreen from './screens/DetailsScreen';
const Stack = createNativeStackNavigator();
export default function App() {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Details" component={DetailsScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
NavigationContainer wraps the entire navigation tree and must appear exactly once,
near the root of your app. Stack.Navigator declares the set of screens available in
this stack, and each Stack.Screen maps a string name (used when
navigating) to the actual component to render.
Navigating Between Screens
Every screen component registered with a navigator automatically receives a
navigation prop, with methods for moving around:
import React from 'react';
import { View, Button } from 'react-native';
export default function HomeScreen({ navigation }) {
return (
<View>
<Button
title="Go to Details"
onPress={() => navigation.navigate('Details')}
/>
</View>
);
}
| Method | Purpose |
|---|---|
navigation.navigate('ScreenName') | Pushes (or jumps to) the named screen |
navigation.goBack() | Pops the current screen off the stack, returning to the previous one |
navigation.push('ScreenName') | Always pushes a new instance of a screen, even the same one already on the stack |
Passing Parameters to a Screen
A second argument to navigate lets you pass data along to the destination screen —
for example, which item's details to show:
// On the sending screen (e.g. a list item's onPress)
navigation.navigate('Details', { itemId: 42, title: 'Wireless Mouse' });
The receiving screen reads them back off a route prop, which every screen also
receives automatically:
import React from 'react';
import { View, Text } from 'react-native';
export default function DetailsScreen({ route }) {
const { itemId, title } = route.params;
return (
<View>
<Text>Item #{itemId}: {title}</Text>
</View>
);
}
route.params is simply the object you passed as the second argument to
navigate — plain JavaScript data flowing from one screen to the next.
The Tab Navigator
For a bottom tab bar — the row of icons at the bottom of the screen switching between top-level
sections of an app (Home, Search, Profile, etc.) — the equivalent package is
@react-navigation/bottom-tabs:
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import HomeScreen from './screens/HomeScreen';
import SettingsScreen from './screens/SettingsScreen';
const Tab = createBottomTabNavigator();
export default function App() {
return (
<NavigationContainer>
<Tab.Navigator>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Settings" component={SettingsScreen} />
</Tab.Navigator>
</NavigationContainer>
);
}
The shape is identical to the Stack Navigator — a navigator component containing
Screen children — just a different create*Navigator() function
producing a different visual pattern (tabs instead of a pushed/popped stack).
Nesting Navigators
Real apps commonly nest navigators inside one another. A very typical pattern: a Tab Navigator forms the app's main shell, and one of its tabs — say, the "Home" tab — itself contains a full Stack Navigator, so that tapping into a list item from the Home tab pushes a details screen on top, without leaving the Home tab or disturbing the other tabs:
// Conceptual shape — a Stack Navigator living inside one Tab screen
function HomeStack() {
return (
<Stack.Navigator>
<Stack.Screen name="HomeList" component={HomeListScreen} />
<Stack.Screen name="Details" component={DetailsScreen} />
</Stack.Navigator>
);
}
function RootTabs() {
return (
<Tab.Navigator>
<Tab.Screen name="HomeTab" component={HomeStack} />
<Tab.Screen name="SettingsTab" component={SettingsScreen} />
</Tab.Navigator>
);
}
This is conceptual awareness for now — the important takeaway is that navigators compose just like any other React components, and combining a top-level Tab Navigator with per-tab Stack Navigators is an extremely common shape for real, production apps.