Bird
Raised Fist0
React Nativemobile~7 mins

Custom tab bars in React Native

Choose your learning style10 modes available
Introduction

Custom tab bars let you change how the bottom navigation looks and works in your app. This helps make your app unique and easier to use.

You want to add icons and text with special colors in your app's bottom tabs.
You want to change the shape or style of the tab bar to match your brand.
You want to add animations or badges on tabs to show notifications.
You want to control what happens when a tab is pressed, like showing a message.
You want to hide or show the tab bar on certain screens.
Syntax
React Native
function MyTabBar({ state, descriptors, navigation }) {
  return (
    <View style={{ flexDirection: 'row' }}>
      {state.routes.map((route, index) => {
        const isFocused = state.index === index;
        const onPress = () => {
          const event = navigation.emit({
            type: 'tabPress',
            target: route.key,
            canPreventDefault: true
          });
          if (!isFocused && !event.defaultPrevented) {
            navigation.navigate(route.name);
          }
        };
        return (
          <TouchableOpacity
            key={route.key}
            onPress={onPress}
            style={{ flex: 1, padding: 10, backgroundColor: isFocused ? '#ddd' : '#fff' }}
          >
            <Text>{route.name}</Text>
          </TouchableOpacity>
        );
      })}
    </View>
  );
}

The state object tells which tab is active and the list of tabs.

The navigation object lets you move between tabs.

Examples
A very simple tab bar with just text buttons for each tab.
React Native
function SimpleTabBar({ state, navigation }) {
  return (
    <View style={{ flexDirection: 'row' }}>
      {state.routes.map((route, index) => (
        <TouchableOpacity
          key={route.key}
          onPress={() => navigation.navigate(route.name)}
          style={{ flex: 1, padding: 10 }}
        >
          <Text>{route.name}</Text>
        </TouchableOpacity>
      ))}
    </View>
  );
}
This tab bar changes background and text color for the active tab.
React Native
function ColoredTabBar({ state, navigation }) {
  return (
    <View style={{ flexDirection: 'row' }}>
      {state.routes.map((route, index) => {
        const isFocused = state.index === index;
        return (
          <TouchableOpacity
            key={route.key}
            onPress={() => navigation.navigate(route.name)}
            style={{
              flex: 1,
              padding: 10,
              backgroundColor: isFocused ? 'skyblue' : 'white'
            }}
          >
            <Text style={{ color: isFocused ? 'white' : 'black' }}>{route.name}</Text>
          </TouchableOpacity>
        );
      })}
    </View>
  );
}
Sample App

This app shows two tabs: Home and Settings. The custom tab bar changes the background color of the active tab to purple and text to white. Other tabs have white background and black text.

React Native
import React from 'react';
import { View, Text, TouchableOpacity } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';

function HomeScreen() {
  return <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}><Text>Home Screen</Text></View>;
}

function SettingsScreen() {
  return <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}><Text>Settings Screen</Text></View>;
}

function MyTabBar({ state, descriptors, navigation }) {
  return (
    <View style={{ flexDirection: 'row', backgroundColor: '#eee' }}>
      {state.routes.map((route, index) => {
        const isFocused = state.index === index;
        const onPress = () => {
          const event = navigation.emit({ type: 'tabPress', target: route.key, canPreventDefault: true });
          if (!isFocused && !event.defaultPrevented) {
            navigation.navigate(route.name);
          }
        };
        return (
          <TouchableOpacity
            key={route.key}
            onPress={onPress}
            style={{ flex: 1, padding: 15, backgroundColor: isFocused ? '#6200ee' : '#fff' }}
            accessibilityRole="button"
            accessibilityState={isFocused ? { selected: true } : {}}
            accessibilityLabel={descriptors[route.key].options.tabBarAccessibilityLabel}
            testID={descriptors[route.key].options.tabBarTestID}
          >
            <Text style={{ color: isFocused ? 'white' : 'black', textAlign: 'center' }}>{route.name}</Text>
          </TouchableOpacity>
        );
      })}
    </View>
  );
}

const Tab = createBottomTabNavigator();

export default function App() {
  return (
    <NavigationContainer>
      <Tab.Navigator tabBar={props => <MyTabBar {...props} />}>
        <Tab.Screen name="Home" component={HomeScreen} />
        <Tab.Screen name="Settings" component={SettingsScreen} />
      </Tab.Navigator>
    </NavigationContainer>
  );
}
OutputSuccess
Important Notes

Always add accessibility props like accessibilityRole and accessibilityState for better screen reader support.

You can add icons or badges inside the tab buttons to improve UI.

Remember to handle the tabPress event to allow default navigation behavior.

Summary

Custom tab bars let you design your own bottom navigation look and feel.

You get the current tab info from state and control navigation with navigation.

Use TouchableOpacity or similar to make tabs clickable.

Practice

(1/5)
1. What is the main purpose of a custom tab bar in React Native navigation?
easy
A. To replace the entire navigation stack with a new one
B. To disable navigation between screens
C. To create a personalized look and behavior for the bottom navigation tabs
D. To automatically fetch data for each tab

Solution

  1. Step 1: Understand what a tab bar does

    A tab bar shows navigation options at the bottom of the screen for switching between views.
  2. Step 2: Identify the role of a custom tab bar

    A custom tab bar lets you change how these tabs look and behave, instead of using the default style.
  3. Final Answer:

    To create a personalized look and behavior for the bottom navigation tabs -> Option C
  4. Quick Check:

    Custom tab bar = personalized navigation UI [OK]
Hint: Custom tab bars change appearance and interaction of bottom tabs [OK]
Common Mistakes:
  • Thinking it replaces navigation logic entirely
  • Assuming it disables navigation
  • Confusing it with data fetching
2. Which React Native component is commonly used to make a tab clickable in a custom tab bar?
easy
A. View
B. TouchableOpacity
C. TextInput
D. ScrollView

Solution

  1. Step 1: Identify clickable components

    TouchableOpacity is designed to respond to touch events and provide feedback.
  2. Step 2: Match with tab interaction needs

    Tabs need to be clickable to switch screens, so TouchableOpacity is the right choice.
  3. Final Answer:

    TouchableOpacity -> Option B
  4. Quick Check:

    Clickable tab = TouchableOpacity [OK]
Hint: Use TouchableOpacity for clickable tabs in React Native [OK]
Common Mistakes:
  • Using View which is not clickable by default
  • Choosing TextInput which is for text input
  • Using ScrollView which is for scrolling content
3. Given this snippet inside a custom tab bar component:
state.index === 1 ? 'blue' : 'gray'
What does this expression do?
medium
A. Causes a syntax error because of missing parentheses
B. Always sets the tab color to gray
C. Changes the tab color to blue when the app starts
D. Sets the tab color to blue if it is the active tab, otherwise gray

Solution

  1. Step 1: Understand the ternary expression

    The expression checks if state.index equals 1; if true, it returns 'blue', else 'gray'.
  2. Step 2: Relate to tab color logic

    This means the tab at index 1 is highlighted blue when active, others are gray.
  3. Final Answer:

    Sets the tab color to blue if it is the active tab, otherwise gray -> Option D
  4. Quick Check:

    state.index === 1 ? 'blue' : 'gray' = active tab color logic [OK]
Hint: Ternary ? : chooses color based on active tab index [OK]
Common Mistakes:
  • Thinking it always returns gray
  • Assuming it causes syntax error
  • Confusing the condition with app start
4. Identify the error in this custom tab bar code snippet:
const CustomTabBar = ({ state, navigation }) => {
  return (
    <View>
      {state.routes.map((route, index) => (
        <TouchableOpacity
          key={index}
          onPress={() => navigation.navigate(route.name)}
        >
          <Text>{route.name}</Text>
        </TouchableOpacity>
      ))}
    </View>
  );
};
medium
A. Missing accessibility props for TouchableOpacity
B. Using index as key causes navigation errors
C. Incorrect use of navigation.navigate inside onPress
D. No error, code works correctly

Solution

  1. Step 1: Review accessibility best practices

    TouchableOpacity should have accessibilityRole and accessibilityState for screen readers.
  2. Step 2: Check other parts of code

    Using index as key is not ideal but won't cause navigation errors; navigation.navigate usage is correct.
  3. Final Answer:

    Missing accessibility props for TouchableOpacity -> Option A
  4. Quick Check:

    Accessibility props missing = error [OK]
Hint: Always add accessibilityRole and accessibilityState to touchables [OK]
Common Mistakes:
  • Ignoring accessibility props
  • Thinking index key breaks navigation
  • Assuming navigation.navigate is wrong here
5. You want to create a custom tab bar that highlights the active tab with a bold label and changes the icon color. Which approach correctly uses state and navigation to achieve this?
hard
A. Use state.index to check active tab, and navigation.navigate(route.name) on press; style label bold if active
B. Use navigation.state.index to check active tab, and state.navigate(route.name) on press; style label bold if active
C. Use state.activeTab to check active tab, and navigation.goBack() on press; style label bold if active
D. Use state.index to check active tab, and navigation.push(route.key) on press; style label bold if active

Solution

  1. Step 1: Identify correct state usage

    The active tab index is in state.index, not navigation.state or state.activeTab.
  2. Step 2: Identify correct navigation method

    navigation.navigate(route.name) is used to switch tabs; goBack or push are not appropriate here.
  3. Step 3: Apply styling based on active tab

    Compare current index with tab index to apply bold style and change icon color.
  4. Final Answer:

    Use state.index to check active tab, and navigation.navigate(route.name) on press; style label bold if active -> Option A
  5. Quick Check:

    state.index + navigation.navigate = correct tab control [OK]
Hint: Use state.index for active tab and navigation.navigate for switching [OK]
Common Mistakes:
  • Using wrong property like navigation.state.index
  • Using navigation.goBack instead of navigate
  • Using state.activeTab which doesn't exist
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard