Tab navigator
Perhaps the most common navigation style in mobile apps is tab-based navigation. These can be tabs at the bottom of the screen or at the top below the heading (or even instead of the heading).
This guide coverscreateBottomTabNavigator. You can also usecreateMaterialBottomTabNavigator or createMaterialTopTabNavigator to add tabs to your application.
Before proceeding, first install @response-navigation/bottom-tabs:
- npm
- Yarn
- pnpm
npm install @react-navigation/bottom-tabs@next
yarn add @react-navigation/bottom-tabs@next
pnpm add @react-navigation/bottom-tabs@next
A minimal example of tab navigation
import * as React from 'react'
import { Text, View } from 'react-native'
import { NavigationContainer } from '@react-navigation/native'
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'
const HomeScreen = () => (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Home!</Text>
</View>
)
const SettingsScreen = () => (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Settings!</Text>
</View>
)
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>
)
}
Customizing appearance
This is similar to how you set up the stack navigator - some properties are set when the tab navigator is initialized, while others can be configured per screen in options.
// You can import Ionicons from @expo/vector-icons if you use Expo or
// react-native-vector-icons/Ionicons otherwise.
import * as React from 'react'
import { Text, View } from 'react-native'
import Ionicons from 'react-native-vector-icons/Ionicons'
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'
import { NavigationContainer } from '@react-navigation/native'
function HomeScreen() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Home!</Text>
</View>
)
}
function SettingsScreen() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Settings!</Text>
</View>
)
}
const Tab = createBottomTabNavigator()
export default function App() {
return (
<NavigationContainer>
<Tab.Navigator
screenOptions={({ route }) => ({
tabBarIcon: ({ focused, color, size }) => {
let iconName
if (route.name === 'Home') {
iconName = focused ? 'ios-information-circle' : 'ios-information-circle-outline'
} else if (route.name === 'Settings') {
iconName = focused ? 'ios-list-box' : 'ios-list'
}
// You can return any component that you like here!
return <Ionicons name={iconName} size={size} color={color} />
},
tabBarActiveTintColor: 'tomato',
tabBarInactiveTintColor: 'gray'
})}
>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Settings" component={SettingsScreen} />
</Tab.Navigator>
</NavigationContainer>
)
}
Let's break it down:
tabBarIcon
is a supported option in the bottom tab navigator. So, we know we can use it in our screen components in theoptions
prop, but in this case we decided to put it in thescreenOptions
prop in theTab.Navigator
to centralize the icon configuration for convenience.tabBarIcon
is a function that sets the state parametersfocused
,color
andsize
. If you look further in the configuration, you will seetabBarOptions
,activeTintColor
andinactiveTintColor
. The defaults are the defaults for the iOS platform, but you can change them here. The color that is passed totabBarIcon
can be active or inactive, depending on the state in focus (focused active). Size is the size of the icon expected by the tab bar.Read the complete API reference for more information on the
createBottomTabNavigator
configuration options.
Add icons to icons
Sometimes we want to add icons to some icons. To do this, you can use the tabBarBadge
parameter:
<Tab.Screen name="Home" component={HomeScreen} options={{ tabBarBadge: 3 }} />
From a UI perspective, this component is ready to use, but you still need to find a way to properly pass the icon counter from somewhere else, for example with React Context, Redux, MobX or event emitters.
Switching between tabs
The familiar navigation.navigate
API is used to switch from one tab to another.
const HomeScreen = ({ navigation }) => {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Home!</Text>
<Button
title="Go to Settings"
onPress={() => navigation.navigate('Settings')}
/>
</View>
)
}
const SettingsScreen = ({ navigation }) => {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Settings!</Text>
<Button title="Go to Home" onPress={() => navigation.navigate('Home')} />
</View>
)
}
Stack navigator for each tab
Usually, tabs don't just display one screen - for example, in your Twitter feed, you can click on a tweet and it will take you to a new screen inside that tab with all the replies. You can think of this as having separate navigation stacks inside each tab, and this is how we will model them in React Navigation.
import * as React from 'react'
import { Button, Text, View } from 'react-native'
import { NavigationContainer } from '@react-navigation/native'
import { createStackNavigator } from '@react-navigation/stack'
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'
const DetailsScreen = () => {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Details!</Text>
</View>
)
}
const HomeScreen = ({ navigation }) => {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Home screen</Text>
<Button
title="Go to Details"
onPress={() => navigation.navigate('Details')}
/>
</View>
)
}
const SettingsScreen = ({ navigation }) => {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Settings screen</Text>
<Button
title="Go to Details"
onPress={() => navigation.navigate('Details')}
/>
</View>
)
}
const HomeStack = createStackNavigator()
const HomeStackScreen = () => {
return (
<HomeStack.Navigator>
<HomeStack.Screen name="Home" component={HomeScreen} />
<HomeStack.Screen name="Details" component={DetailsScreen} />
</HomeStack.Navigator>
)
}
const SettingsStack = createStackNavigator()
const SettingsStackScreen = () => {
return (
<SettingsStack.Navigator>
<SettingsStack.Screen name="Settings" component={SettingsScreen} />
<SettingsStack.Screen name="Details" component={DetailsScreen} />
</SettingsStack.Navigator>
)
}
const Tab = createBottomTabNavigator();
const App = () => {
return (
<NavigationContainer>
<Tab.Navigator>
<Tab.Screen name="Home" component={HomeStackScreen} />
<Tab.Screen name="Settings" component={SettingsStackScreen} />
</Tab.Navigator>
</NavigationContainer>
)
}
export default App
Done
To see how well you learned this lesson, take the test in our school's mobile app on this topic or in Telegram bot.
Links
Contributors ✨
Thanks goes to these wonderful people (emoji key):
Dmitriy Vasilev 💲 |