React Native makes it easy to build native mobile apps using JavaScript and React. But as your app grows, so does the need for structured navigation. Whether you’re switching screens, managing nested routes, or implementing a tab layout, navigation plays a key role in building intuitive mobile experiences.
In this tutorial, you'll learn how to set up navigation in a React Native app using the popular React Navigation library, with examples of stack navigation, tab navigation, and drawer navigation.
Prerequisites
Before you begin, make sure you have the following installed:
- Node.js and npm
- React Native CLI or Expo CLI
- A physical device or emulator (Android or iOS)
Create a New React Native App
For this tutorial, we’ll use React Native CLI. Run:
npx @react-native-community/cli init RNNavigationExample
cd RNNavigationExample
Alternatively, if you prefer Expo, run:
npx create-expo-app RNNavigationExample
cd RNNavigationExample
Installing React Navigation
Install the core libraries:
npm install @react-navigation/native
Then install the required dependencies:
npm install react-native-screens react-native-safe-area-context react-native-gesture-handler react-native-reanimated
For stack, tab, and drawer navigators:
npm install @react-navigation/native-stack
npm install @react-navigation/bottom-tabs
npm install @react-navigation/drawer
To complete setup of react-native-reanimated, in babel.config.js add:
module.exports = {
presets: ['module:@react-native/babel-preset'],
plugins: ['react-native-reanimated/plugin'],
};
Don’t forget to wrap your app in the navigation provider:
import * as React from 'react';
import { NavigationContainer } from '@react-navigation/native';
export default function App() {
return (
<NavigationContainer>
{/* Navigators will go here */}
</NavigationContainer>
);
}
To keep things organized, you can use this folder layout:
/RNNavigationExample
├── /screens
│ ├── HomeScreen.js
│ └── DetailsScreen.js
├── /navigators
│ ├── StackNavigator.js
│ ├── TabNavigator.js
│ └── DrawerNavigator.js
└── App.tsx
Stack Navigation Example
Stack navigation lets you push and pop screens like a stack of cards. Create a new navigators folder and StackNavigator.js file, then add:
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import HomeScreen from './screens/HomeScreen';
import DetailsScreen from './screens/DetailsScreen';
const Stack = createNativeStackNavigator();
export default function StackNavigator() {
return (
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Details" component={DetailsScreen} />
</Stack.Navigator>
);
}
Create a new folder, screens, and HomeScreen.js, then add:
import React from 'react';
import { View, Text, Button } from 'react-native';
import PropTypes from 'prop-types';
const HomeScreen = ({ navigation }) => {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Welcome to the Home Screen</Text>
<Button
title="Go to Details"
onPress={() => navigation.navigate('Details', { id: 42 })}
/>
</View>
);
};
HomeScreen.propTypes = {
navigation: PropTypes.object.isRequired,
};
export default HomeScreen;
Create a new DetailsScreen.js, then add:
import React from 'react';
import { View, Text } from 'react-native';
import PropTypes from 'prop-types';
const DetailsScreen = ({ route }) => {
const { id } = route.params || {};
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Details Screen</Text>
<Text>ID: {id}</Text>
</View>
);
};
DetailsScreen.propTypes = {
route: PropTypes.shape({
params: PropTypes.shape({
id: PropTypes.number,
}),
}).isRequired,
};
export default DetailsScreen;
Update the App.tsx.
import * as React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import StackNavigator from './StackNavigator';
export default function App() {
return (
<NavigationContainer>
<StackNavigator />
</NavigationContainer>
);
}
Run the application on the device.
npx react-native run-android
Tab Navigation Example
Tab navigation allows users to switch between different sections of the app. Create a new navigators/TabNavigator.js file, then add:
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import HomeScreen from './screens/HomeScreen';
import SettingsScreen from './screens/SettingsScreen';
const Tab = createBottomTabNavigator();
export default function TabNavigator() {
return (
<Tab.Navigator>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Settings" component={SettingsScreen} />
</Tab.Navigator>
);
}
Create a new screens/SettingsScreen.js, then add:
import React from 'react';
import { View, Text } from 'react-native';
const SettingsScreen = () => {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Settings Screen</Text>
</View>
);
};
export default SettingsScreen;
Update the App.tsx.
import * as React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import TabNavigator from './navigators/TabNavigator';
export default function App() {
return (
<NavigationContainer>
<TabNavigator />
</NavigationContainer>
);
}
Drawer Navigation Example
Drawer navigation enables a sliding menu from the side, which is commonly used for navigation drawers. Create a new navigators/DrawerNavigator.js, then add:
import { createDrawerNavigator } from '@react-navigation/drawer';
import HomeScreen from './screens/HomeScreen';
import ProfileScreen from './screens/ProfileScreen';
const Drawer = createDrawerNavigator();
export default function DrawerNavigator() {
return (
<Drawer.Navigator>
<Drawer.Screen name="Home" component={HomeScreen} />
<Drawer.Screen name="Profile" component={ProfileScreen} />
</Drawer.Navigator>
);
}
Create a new screens/ProfileScreen.js, then add:
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
const ProfileScreen = () => {
return (
<View style={styles.container}>
<Text>Profile Screen</Text>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
});
export default ProfileScreen;
Update the App.tsx.
import * as React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import DrawerNavigator from './navigators/DrawerNavigator';
export default function App() {
return (
<NavigationContainer>
<DrawerNavigator />
</NavigationContainer>
);
}
Combining Navigators (Advanced)
You can also nest navigators to create complex navigation flows, such as a tab bar with stack screens inside each tab. Update navigators/TabNavigator.js:
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import StackNavigator from './StackNavigator';
import DrawerNavigator from './DrawerNavigator';
const Tab = createBottomTabNavigator();
export default function TabNavigator() {
return (
<Tab.Navigator>
<Tab.Screen name="Home" component={StackNavigator} />
<Tab.Screen name="Settings" component={DrawerNavigator} />
</Tab.Navigator>
);
}
Update the App.tsx.
import * as React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import TabNavigator from './navigators/TabNavigator';
export default function App() {
return (
<NavigationContainer>
<TabNavigator />
</NavigationContainer>
);
}
Adding Deep Linking to React Native Navigation
Deep linking allows your app to respond to URLs — for example, opening myapp://details/42 can take users directly to the Details screen with an ID of 42.
- This is especially useful for:
- Push notifications
- Opening screens from email or external links
- Sharing specific content in your app
Step 1: Configure URL Scheme
For deep linking to work, you must define a custom URL scheme in your native code.
On Android
Edit android/app/src/main/AndroidManifest.xml:
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="myapp" android:host="app" />
</intent-filter>
On iOS
In ios/[yourProject]/Info.plist, add:
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>myapp</string>
</array>
</dict>
</array>
Step 2: Set Up Linking Configuration in React Navigation
Create a linking configuration in your App.tsx:
import * as React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import StackNavigator from './navigators/StackNavigator';
export default function App() {
const linking = {
prefixes: ['myapp://'],
config: {
screens: {
Home: 'home',
Details: 'details/:id',
Profile: 'user/:username',
},
},
};
return (
<NavigationContainer linking={linking}>
<StackNavigator />
</NavigationContainer>
);
}
Step 3: Test Deep Links
You can simulate deep links in development:
Android
adb shell am start -W -a android.intent.action.VIEW -d "myapp://details/42" com.rnnavigationexample
iOS (Simulator)
xcrun simctl openurl booted "myapp://details/42"
If your DetailsScreen uses route params:
function DetailsScreen({ route }) {
const { id } = route.params;
return <Text>Detail ID: {id}</Text>;
}
Result
Now, when you open myapp://details/42, your app will launch (if installed) and navigate directly to the Details screen with id = 42.
Add Custom Navigation Animations in React Native
Prerequisites
Ensure you’re using:
@react-navigation/native-stack (which uses react-native-screens)
Or
react-navigation/stack with gesture and animation support
Since you're using @react-navigation/native-stack, we’ll use that for smooth and performant native-style animations.
Step 1: Enable Native Stack Navigation Transitions
If you're not already doing this, make sure your stack navigator is using createNativeStackNavigator:
import { createNativeStackNavigator } from '@react-navigation/native-stack';
const Stack = createNativeStackNavigator();
Step 2: Apply Custom Animations per Screen
You can customize animations per screen using the animation, animationTypeForReplace, and gestureDirection options.
Example: Slide from the bottom
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen
name="Details"
component={DetailsScreen}
options={{
animation: 'slide_from_bottom',
}}
/>
</Stack.Navigator>
Other animation values:
- 'default'
- 'fade'
- 'flip'
- 'none'
- 'slide_from_right'
- 'slide_from_left'
- 'slide_from_bottom'
- 'fade_from_bottom'
Step 3: Set Global Stack Animations
To use a consistent animation throughout your stack:
<Stack.Navigator
screenOptions={{
animation: 'slide_from_right',
gestureEnabled: true,
}}
>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Details" component={DetailsScreen} />
</Stack.Navigator>
Bonus: Conditional Animation Example
<Stack.Screen
name="Profile"
component={ProfileScreen}
options={({ route }) => ({
animation: route.params?.fromSettings ? 'slide_from_bottom' : 'fade',
})}
/>
For Tabs and Drawers
Tabs and drawers come with built-in animations, but you can adjust some transition settings like this:
<Tab.Navigator
screenOptions={{
tabBarHideOnKeyboard: true,
tabBarStyle: {
transitionDuration: '0.3s',
},
}}
>
For drawers, animation is built-in, but you can use:
<Drawer.Navigator
screenOptions={{
drawerType: 'slide', // or 'front', 'back', 'permanent'
}}
>
Styling Navigation Components in React Native
In this section, we’ll style the header, tab bar, and drawer using options provided by React Navigation.
Stack Navigator Styling
Customize the stack headers using screenOptions.
<Stack.Navigator
screenOptions={{
headerStyle: {
backgroundColor: '#6200ee',
},
headerTintColor: '#fff',
headerTitleStyle: {
fontWeight: 'bold',
},
contentStyle: {
backgroundColor: '#f5f5f5',
},
}}
>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Details" component={DetailsScreen} />
</Stack.Navigator>
Tab Navigator Styling
You can style the tab bar and active/inactive icons like this:
<Tab.Navigator
screenOptions={{
tabBarHideOnKeyboard: true,
tabBarStyle: {
transitionDuration: '0.3s',
backgroundColor: '#fff',
borderTopWidth: 0,
elevation: 10,
},
tabBarActiveTintColor: '#6200ee',
tabBarInactiveTintColor: '#888',
tabBarLabelStyle: {
fontSize: 12,
},
headerShown: false,
}}
>
<Tab.Screen name="Home" component={StackNavigator} />
<Tab.Screen name="Settings" component={DrawerNavigator} />
</Tab.Navigator>
Drawer Navigator Styling
<Drawer.Navigator
screenOptions={{
drawerType: 'slide',
drawerStyle: {
backgroundColor: '#f0f0f0',
width: 240,
},
drawerActiveBackgroundColor: '#6200ee',
drawerActiveTintColor: '#fff',
drawerInactiveTintColor: '#333',
headerStyle: {
backgroundColor: '#6200ee',
},
headerTintColor: '#fff',
}}
>
<Drawer.Screen name="Home" component={HomeScreen} />
<Drawer.Screen name="Profile" component={ProfileScreen} />
</Drawer.Navigator>
Tips for Clean UI
- Stick to your design system or use a color theme consistently
- Use shadow/elevation only where needed to avoid clutter
- Use SafeAreaView for proper spacing on iOS
Custom Fonts and Icons
You can use libraries like react-native-vector-icons and Google Fonts for custom header or tab styles:
npm install react-native-vector-icons
Example with an icon in the header:
<Stack.Screen
name="Home"
component={HomeScreen}
options={{
title: 'Dashboard',
headerRight: () => (
<Ionicons name="notifications-outline" size={24} color="#fff" style={{ marginRight: 15 }} />
),
}}
/>
Conclusion
In this comprehensive guide, you learned how to master navigation in React Native using @react-navigation with Stack, Tabs, and Drawer navigators. We went beyond basic routing by adding deep linking, custom animations, and styling, giving you the tools to build smooth and intuitive navigation experiences that align with your app’s design.
With this solid foundation, you’re ready to scale your app with authentication flows, protected routes, and advanced navigation patterns. Whether you're building a simple app or a complex multi-screen experience, React Navigation provides all the flexibility and performance you need.
Next, consider implementing authentication flows with Firebase and React Navigation to manage login and protected screens.
You can find the full source code on our GitHub.
That's just the basics. If you need more deep learning about React.js, React Native, or related, you can take the following cheap course:
- Master React Native Animations
- Advanced React Native Topics
- React Native
- Learning React Native Development
- React: React Native Mobile Development: 3-in-1
Thanks!