Navigating between screens is an essential part of any mobile application. In this blog, I'll guide you step-by-step on how to integrate Stack Navigator and Bottom Tab Navigator into your React Native project using @react-navigation
.
Prerequisites
Before we begin, ensure you have the following setup:
- Create a React Native project using
npx @react-native-community/cli init projectName
. - Follow the React Navigation Docs to set up the required dependencies. For this guide, use the following packages:
"@react-navigation/bottom-tabs": "^7.2.0",
"@react-navigation/elements": "^2.2.5",
"@react-navigation/native": "^7.0.14",
"@react-navigation/native-stack": "^7.2.0",
"@react-navigation/stack": "^7.1.1",
"react": "18.3.1",
"react-native": "0.76.6",
"react-native-gesture-handler": "^2.22.0",
"react-native-safe-area-context": "^5.1.0",
"react-native-screens": "^4.5.0",
Project Structure
Organize your project in the following way for better readability:
src/
├── screens/
│ ├── HomeScreen.js
│ ├── ProfileScreen.js
│ ├── DetailScreen.js
│ ├── SettingScreen.js
├── navigation/
│ ├── bottomNavigator.js
│ ├── rootNavigator.js
│ ├── styles.js
│ ├── navigators/
│ ├── detailStackNavigator.js
│ ├── homeStackNavigator.js
│ ├── profileStackNavigator.js
│ ├── settingStackNavigator.js
Screenshot for the reference
Step 1: Setup App.js
In App.js
, wrap your main navigator
with the SafeAreaProvider
for better handling of device-specific safe areas.
import React from 'react';
import MainNavigator from './src/navigation/rootNavigator';
import { SafeAreaProvider } from 'react-native-safe-area-context';
const App = () => {
return (
<SafeAreaProvider>
<MainNavigator />
</SafeAreaProvider>
);
};
export default App;
Step 2: Create Screens
Inside src/screens
, create the following components:
Example: HomeScreen.js
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
const HomeScreen = () => {
return (
<View style={styles.container}>
<Text>Home Screen</Text>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
});
export default HomeScreen;
Repeat this process for ProfileScreen
, DetailScreen
, and SettingScreen
, changing the displayed text accordingly.
Step 3: Create the Bottom Tab Navigator
In src/navigation/bottomNavigator.js
, set up the Bottom Tab Navigator with custom icons for each tab.
import {View} from 'react-native';
import React from 'react';
import {
BottomTabBar,
createBottomTabNavigator,
} from '@react-navigation/bottom-tabs';
import styles from './styles';
import {
DetailAltIcon,
DetailIcon,
HomeAltIcon,
HomeIcon,
ProfileAltIcon,
ProfileIcon,
SettingAltIcon,
SettingIcon,
} from '../assets';
import HomeStack from './navigators/homeStackNavigator';
import DetailStack from './navigators/detailStackNavigator';
import SettingStack from './navigators/settingStackNavigator';
import ProfileStack from './navigators/profileStackNavigator';
const BottomNavigator = () => {
let WIDTH = 25;
let HEIGHT = 25;
const BottomTabNavigator = createBottomTabNavigator();
const tabBarListeners = ({navigation, route}) => ({
tabPress: () => navigation.navigate(route.name),
});
return (
<BottomTabNavigator.Navigator
tabBar={props => (
<View style={styles.wrapperStyle}>
<BottomTabBar {...props} style={styles.bottomTabStyles} />
</View>
)}
screenOptions={{
tabBarActiveTintColor: '#000000',
tabBarInactiveTintColor: '#767676',
tabBarStyle:{
backgroundColor: '#fff',
borderTopWidth: 0,
elevation: 0,
paddingTop: 10,
height: Platform.OS === 'android' ? 65 : null,
},
tabBarLabelStyle: {
fontFamily: "Arial",
fontSize: 11,
},
}}>
<BottomTabNavigator.Screen
options={{
tabBarShowLabel: true,
gestureEnabled: false,
unmountOnBlur: true,
headerShown: false,
tabBarIcon: ({focused}) =>
focused ? (
<HomeAltIcon width={WIDTH} height={HEIGHT} />
) : (
<HomeIcon width={WIDTH} height={HEIGHT} />
),
}}
name="Home"
listeners={tabBarListeners}
component={HomeStack}
/>
<BottomTabNavigator.Screen
options={{
tabBarShowLabel: true,
gestureEnabled: false,
unmountOnBlur: true,
headerShown: false,
tabBarIcon: ({focused}) =>
focused ? (
<SettingAltIcon width={WIDTH} height={HEIGHT} />
) : (
<SettingIcon width={WIDTH} height={HEIGHT} />
),
}}
name="Setting"
listeners={tabBarListeners}
component={SettingStack}
/>
<BottomTabNavigator.Screen
options={{
tabBarShowLabel: true,
gestureEnabled: false,
unmountOnBlur: true,
headerShown: false,
tabBarIcon: ({focused}) =>
focused ? (
<DetailAltIcon width={WIDTH} height={HEIGHT} />
) : (
<DetailIcon width={WIDTH} height={HEIGHT} />
),
}}
name="Detail"
listeners={tabBarListeners}
component={DetailStack}
/>
<BottomTabNavigator.Screen
options={{
tabBarShowLabel: true,
gestureEnabled: false,
unmountOnBlur: true,
headerShown: false,
tabBarIcon: ({focused}) =>
focused ? (
<ProfileAltIcon width={WIDTH} height={HEIGHT} />
) : (
<ProfileIcon width={WIDTH} height={HEIGHT} />
),
}}
name="Profile"
listeners={tabBarListeners}
component={ProfileStack}
/>
</BottomTabNavigator.Navigator>
);
};
export default BottomNavigator;
You can customize the tab bar further, such as adding icons, custom styles, or listeners.
Step 4: Create the Root Navigator
In src/navigation/rootNavigator.js
, create the Stack Navigator and integrate the Bottom Tab Navigator.
import React from 'react';
import {NavigationContainer} from '@react-navigation/native';
import {
CardStyleInterpolators,
createStackNavigator,
} from '@react-navigation/stack';
import BottomNavigator from './bottomNavigator';
import SplashScreen from '../screens/SplashScreen';
import StackFullScreen from '../screens/StackFullScreen';
const Stack = createStackNavigator();
const LoginStack = () => {
return (
<Stack.Navigator
screenOptions={{
headerShown: false,
}}>
<Stack.Screen name="Splash" component={SplashScreen} />
<Stack.Screen name="FullScreen" component={StackFullScreen} />
<Stack.Screen
name="HomeScreen"
component={BottomNavigator}
options={{
cardStyleInterpolator: CardStyleInterpolators.forFadeFromCenter,
gestureEnabled: false,
}}
/>
</Stack.Navigator>
);
};
const MainNavigator = () => {
return (
<NavigationContainer
options={{
gestureEnabled: false,
}}>
<LoginStack />
</NavigationContainer>
);
};
export default MainNavigator;
Step 5: Style the Tab Bar
In src/navigation/styles.js
, define styles for the bottom tab bar.
import { StyleSheet } from 'react-native';
export default StyleSheet.create({
wrapperStyle: {
position: 'absolute',
bottom: 0,
left: 0,
right: 0,
// borderTopLeftRadius: 15,
// borderTopRightRadius: 15,
overflow: 'hidden',
},
bottomTabStyles: {
// borderTopLeftRadius: 15,
// borderTopRightRadius: 15,
},
});
Step 6: Organizing the Navigation
Folder
To maintain a clean and scalable codebase, it's essential to organize your navigation files properly. We'll create a navigators folder within the navigation directory and define stack navigators for the following sections of the app:
detailStackNavigator.js
homeStackNavigator.js
profileStackNavigator.js
settingStackNavigator.js
Folder Structure
Here’s how the project structure looks after this step:
src/
├── screens/
│ ├── HomeScreen.js
│ ├── ProfileScreen.js
│ ├── DetailScreen.js
│ ├── SettingScreen.js
├── navigation/
│ ├── bottomNavigator.js
│ ├── rootNavigator.js
│ ├── styles.js
│ ├── navigators/
│ ├── detailStackNavigator.js
│ ├── homeStackNavigator.js
│ ├── profileStackNavigator.js
│ ├── settingStackNavigator.js
Creating Stack Navigators
Inside the navigators
folder, we will define the stack navigators for each section of the app.
1. Detail Stack Navigator
The detailStackNavigator.js
file manages the stack for the detail section of the app. This includes the DetailScreen
, which serves as the initial screen for this stack.
import React from 'react';
import {
CardStyleInterpolators,
createStackNavigator,
} from '@react-navigation/stack';
import DetailScreen from '../../screens/DetailScreen';
import WithInBottomScreen from '../../screens/WithInBottomScreen';
const Stack = createStackNavigator();
export default function DetailStack() {
return (
<Stack.Navigator
screenOptions={{
headerShown: false,
}}>
<Stack.Screen
name="DetailPage"
component={DetailScreen}
options={{
cardStyleInterpolator: CardStyleInterpolators.forHorizontalIOS,
gestureEnabled: false,
}}
/>
<Stack.Screen name="WithInBottomScreen" component={WithInBottomScreen} />
</Stack.Navigator>
);
}
2. Home Stack Navigator
The homeStackNavigator.js
is responsible for the main app flow, starting with the HomeScreen
.
import React from 'react';
import {
CardStyleInterpolators,
createStackNavigator,
} from '@react-navigation/stack';
import HomeScreen from '../../screens/HomeScreen';
import WithInBottomScreen from '../../screens/WithInBottomScreen';
const Stack = createStackNavigator();
export default function HomeStack() {
return (
<Stack.Navigator
screenOptions={{
headerShown: false,
}}>
<Stack.Screen
name="HomePage"
component={HomeScreen}
options={{
cardStyleInterpolator: CardStyleInterpolators.forHorizontalIOS,
gestureEnabled: false,
}}
/>
<Stack.Screen name="WithInBottomScreen" component={WithInBottomScreen} />
</Stack.Navigator>
);
}
3. Profile Stack Navigator
The profileStackNavigator.js
organizes the profile-related screens, starting with ProfileScreen
.
import React from 'react';
import {
CardStyleInterpolators,
createStackNavigator,
} from '@react-navigation/stack';
import ProfileScreen from '../../screens/ProfileScreen';
import WithInBottomScreen from '../../screens/WithInBottomScreen';
const Stack = createStackNavigator();
export default function ProfileStack() {
return (
<Stack.Navigator
screenOptions={{
headerShown: false,
}}>
<Stack.Screen
name="ProfilePage"
component={ProfileScreen}
options={{
cardStyleInterpolator: CardStyleInterpolators.forHorizontalIOS,
gestureEnabled: false,
}}
/>
<Stack.Screen name="WithInBottomScreen" component={WithInBottomScreen} />
</Stack.Navigator>
);
}
4. Setting Stack Navigator
The settingStackNavigator.js
defines the stack for the app's settings, starting with the SettingScreen
.
import React from 'react';
import {
CardStyleInterpolators,
createStackNavigator,
} from '@react-navigation/stack';
import SettingScreen from '../../screens/SettingScreen';
import WithInBottomScreen from '../../screens/WithInBottomScreen';
const Stack = createStackNavigator();
export default function SettingStack() {
return (
<Stack.Navigator
screenOptions={{
headerShown: false,
}}>
<Stack.Screen
name="SettingPage"
component={SettingScreen}
options={{
cardStyleInterpolator: CardStyleInterpolators.forHorizontalIOS,
gestureEnabled: false,
}}
/>
<Stack.Screen name="WithInBottomScreen" component={WithInBottomScreen} />
</Stack.Navigator>
);
}
Why Use Separate Navigators?
- Modularity: Each navigator focuses on a specific section of the app, making the code easier to manage and debug.
- Scalability: Adding more screens or functionality to a specific section becomes straightforward.
- Reusability: Stack navigators can be combined into other navigators (e.g., bottom tab or root navigators) without redundancy.
Handling Special Cases: Hiding the Bottom Tab Bar
Certain screens, like a full-screen modal or a detail view, may require hiding the bottom tab bar when displayed. Here's an example of how to achieve this.
WithInBottomScreen
The WithInBottomScreen
is an example of a screen where the bottom tab bar is hidden when the user navigates to it. The tab bar is restored when the user navigates away.
import {Button, StyleSheet, Text, View} from 'react-native';
import React, {useEffect} from 'react';
const WithInBottomScreen = ({navigation}) => {
useEffect(() => {
// Hide the bottom tab bar when this screen is active
navigation.getParent()?.setOptions({tabBarStyle: {display: 'none'}});
return () => {
// Restore the bottom tab bar when leaving this screen
navigation.getParent()?.setOptions({
tabBarStyle: {
backgroundColor: '#fff',
borderTopWidth: 0,
elevation: 0,
paddingTop: 10,
height: Platform.OS === 'android' ? 65 : null,
},
});
};
}, [navigation]);
return (
<View style={styles.container}>
<Text>WithInBottomScreen</Text>
<Button title="Go Back" onPress={() => navigation.goBack()} />
</View>
);
};
export default WithInBottomScreen;
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
});
Running the App
- Start your app using:
npx react-native start
npx react-native run-android # for Android
npx react-native run-ios # for iOS
- You should now see a fully functional app with a Bottom Tab Navigator and a Stack Navigator integrated.
Part 2
How to Integrate Stack, Bottom Tab, and Drawer Navigator in React Native
Conclusion
Integrating Stack and Bottom Tab Navigators allows you to create complex navigation flows in your React Native app. This guide provides the foundation, and you can build upon it by adding more screens, customizing navigation, or using advanced features like deep linking or dynamic routes.
After reading the post consider the following:
- Subscribe to receive newsletters with the latest blog posts
- Download the source code for this post from my github
Let me know if you have any questions or need further assistance! 🚀
Top comments (0)