Building an Instagram-Style Bottom Navigation in React Native(Expo)
Building a customized app navigator
Hey there, lovely readers! ๐ It's Cindy Kandie, and I'm back after a refreshing break in August. I know, I know, it wasn't exactly planned, but sometimes life throws you a curveball, right? But fret not, I'm back on track and ready to pick up where we left off with our weekly blog posts. Thanks for always being here!
Embracing My Fate as a Turnt React Native Developer
During my little hiatus, something amazing happened. I accepted my fate and embraced the world of React Native. And guess what? I even snagged a cool title for myself โ Mobile Developer, thanks to React Native! ๐ Today, I'm super excited to share my journey of creating a bottom navigation bar similar to the one you see on Instagram.
Before we dive in, here's what you'll need:
Basic knowledge of React Native.
Familiarity with React.
A sprinkle of Tailwind CSS for styling.
Now, let's get started step by step.
Step 1: Setting Up Your Expo Project
First things first, let's set up our Expo project. You can follow the detailed instructions in the Expo documentation to get started.
Step 2: Installing NativeWind for TailWind
To make our styling life easier, we'll use NativeWind. You can install it by following the guide here.
Step 3: Explaining the Screens
Before we delve into the code, let's briefly discuss the screens you want to include in your bottom navigation. For this example, we have 'Home,' 'Search,' 'Category,' 'Notification,' and 'Profile' screens.
Step 4: Creating the Initial Views
We'll begin with a simple setup of views and no styling. Here's the code to get us started:Note:
To make things easier, I added an array so I can simply map over to display the tab names. I am also using expo/vector-icons, make sure you install these.
import { Text, View, TouchableOpacity } from 'react-native';
import { Ionicons } from '@expo/vector-icons';
function BottomNav() {
const tabItems = [
{ name: 'Home', icon: 'home' },
{ name: 'Search', icon: 'search' },
{ name: 'Category', icon: 'list' },
{ name: 'Notification', icon: 'notifications' },
{ name: 'Profile', icon: 'person' },
];
return (
<View>
{tabItems.map((tab) => (
<TouchableOpacity key={tab.name}>
<Ionicons name={tab.icon} size={24} color="black" />
<Text>{tab.name}</Text>
</TouchableOpacity>
))}
</View>
);
}
export default BottomNav;
Step 5: Adding Styling
Now, let's make it visually appealing with Tailwind CSS. This is where the magic happens. Check out the code below:Note:
Some of the styling has been done using inline styling 'style:{{}}' let's just say that tailwind wasn't responding and gave me a mini-migraine. But all is well :)
import React from 'react';
import { Text, View, TouchableOpacity } from 'react-native';
import { Ionicons } from '@expo/vector-icons';
function BottomNav() {
const tabItems = [
{ name: 'Home', icon: 'home' },
{ name: 'Search', icon: 'search' },
{ name: 'Category', icon: 'list' },
{ name: 'Notification', icon: 'notifications' },
{ name: 'Profile', icon: 'person' },
];
return (
<View
className={`flex-row justify-between items-center bg-cyan-400 p-2 content-evenly bg-white gap-1 px-2 py-0 pb-3`}
style={{
position: 'absolute',
bottom: 0,
left: 0,
right: 0,
zIndex: 20,
}}
>
{tabItems.map((tab) => (
<TouchableOpacity
key={tab.name}
onPress={() => handleTabPress(tab.name)}
className={`flex-1 items-center p-1`}
style={{
alignItems: 'center',
borderTopWidth: activeRouteName === tab.name ? 2 : 0,
borderColor: activeRouteName === tab.name ? 'cyan' : 'transparent',
}}
>
<Ionicons
name={tab.icon}
size={24}
color='black'}
/>
<Text
style={{
fontSize: 12,
paddingTop: 1,
color:'black',
}}
>
{tab.name}
</Text>
</TouchableOpacity>
))}
</View>
);
}
export default BottomNav;
Step 5: Adding the Almighty Functions
Now, let's add the functions that will power our bottom navigation.
- These functions tell the icons and tabs how to behave on click i.e. handling navigation, and which specific screens the entire is supposed to appear on.Note:
I have updated the code to work with these important functions correctly. I have added comments to clear any doubts.
import React, { useState, useContext } from 'react';
import { Text, View, TouchableOpacity } from 'react-native';
import { Ionicons } from '@expo/vector-icons';
import { useNavigationState, useNavigation } from '@react-navigation/native';
function BottomNav() {
// Get the current navigation state and navigation object
const navigationState = useNavigationState((state) => state);
const navigation = useNavigation();
// Determine the active route name
const activeRouteName = navigationState?.routes[navigationState?.index]?.name;
// State to keep track of the selected tab
const [selectedTab, setSelectedTab] = useState(activeRouteName);
// Function to handle tab press
const handleTabPress = (tabName) => {
setSelectedTab(tabName);
navigation.navigate(tabName);
};
// Array of tab items, each with a name and icon
const tabItems = [
{ name: 'Home', icon: 'home' },
{ name: 'Search', icon: 'search' },
{ name: 'Category', icon: 'list' },
{ name: 'Notification', icon: 'notifications' },
{ name: 'Profile', icon: 'person' },
];
// Array of screens to show in the bottom navigation
const screensToShowBottomNav = ['Home', 'Search', 'Category', 'Notification', 'Profile'];
// If the active route is not in the screensToShowBottomNav array, don't render the bottom navigation
if (!screensToShowBottomNav.includes(activeRouteName)) {
return null;
}
return (
<View
// Add styling and class name based on your theme
style={{
position: 'absolute',
bottom: 0,
left: 0,
right: 0,
zIndex: 20,
}}
>
{tabItems.map((tab) => (
<TouchableOpacity
key={tab.name}
onPress={() => handleTabPress(tab.name)}
// Add styling and class name based on your theme
style={{
alignItems: 'center',
borderTopWidth: activeRouteName === tab.name ? 2 : 0,
borderColor: activeRouteName === tab.name ? 'cyan' : 'transparent',
}}
>
<Ionicons
name={tab.icon}
size={24}
color={activeRouteName === tab.name ? 'cyan' : 'black'}
/>
<Text
style={{
fontSize: 12,
paddingTop: 1,
color: activeRouteName === tab.name ? 'cyan' : 'black',
}}
>
{tab.name}
</Text>
</TouchableOpacity>
))}
</View>
);
}
export default BottomNav;
Note:
The tab items array can have another attribute. If you want to customize the tab names appearing on the UI, you can add a 'handle' (for example) attribute in the tab item object and use it for naming the tab other than the actual screen name.
const tabItems = [
{ handle: 'Feed', name: 'Home', icon: 'home' },
{ handle: 'Search', name: 'Search', icon: 'search' },
{ handle: 'Categories', name: 'Category', icon: 'list' },
{ handle: 'Notifications', name: 'Notification', icon: 'notifications' },
{ handle: 'User', name: 'Profile', icon: 'person' },
// You can add more tab items with custom names if needed.
];
//on the tab name section
<Text
style={{
fontSize: 12,
paddingTop: 1,
color: activeRouteName === tab.name ? 'cyan' : theme.textColor,
}}
>
{tab.handle}
</Text>
Step 7: Placing the Component
To complete the process, make sure to include your BottomNav
component in your App.js
(or equivalent) to ensure it's rendered throughout your app.
export default function App() {
return (
<NavigationContainer>
<StatusBar style="light" />
<AuthContextProvider>
<Root /> //Probably with the main stack navigator
<BottomNav/>
</AuthContextProvider>
</NavigationContainer>
);
}
And there you have it, folks! You've just created an Instagram-style bottom navigation bar for your React Native app ๐ Feel free to customize it further to match your app's unique style.
What's Next?
In our next adventure(and I mean blog) together, we'll dive deeper into React Native and explore more cool features and tricks to level up your mobile app development game.
Stay tuned for that! And more thanks for being here and learning with me.
Until then, happy coding, and may your Development journey be as fun as mine.