Search
⌘K
    to navigateEnterto select Escto close

    Using Nested Navigators

    Stack and Tab Navigators

    What is a Stack Navigator?

    A Stack Navigator provides a way for your app to transition between screens where each new screen is placed on top of a stack.

    What is a Tab Navigator?

    A Tab Navigator is a simple tab bar at the bottom of the screen that lets you switch between different routes. Routes are lazily initialized -- their screen components are not mounted until they are first focused.

    In this article we will learn to use nested navigators in react native by placing a stack navigator inside a tab navigator.

    Setting Up

    yarn add @react-navigation/native @react-navigation/bottom-tabs @react-navigation/stack

    We want to create a navigation structure as follows:

    nested-navigators-RN

    Create a file, src/navigation/Navigation.js, where we will manage navigation for the app.

    src-structure

    Building Stacks

    Say I want to add tab icons for Home and Details in the Tab Navigator. From the Details tab I should be able to navigate to an inner screen named InnerDetails.js. So we will need to create separate stacks using the Stack Navigator for the two tabs that we want.

    We want only one screen for the Home tab, which is the loaded by default when the app starts. The HomeStack would define that screen as follows:

    1import { createStackNavigator } from "@react-navigation/stack";
    2import Home from "@screens/Home";
    3
    4const HomeStack = createStackNavigator();
    5const screenNames = {
    6  home: "Home",
    7};
    8
    9function HomeStackScreen() {
    10  return (
    11    <HomeStack.Navigator
    12      headerMode="none"
    13      screenOptions={{
    14        gestureEnabled: true,
    15        gestureDirection: "horizontal",
    16      }}
    17      initialRouteName={screenNames.home}
    18    >
    19      <HomeStack.Screen name={screenNames.home} component={Home} />
    20    </HomeStack.Navigator>
    21  );
    22}

    Next we want a Details tab button for navigating to the Details screen. Inside that screen we want a button that will display an inner screen named InnerDetails.js.

    We will hide our Tab bar in this particular screen with getFocusedRouteNameFromRoute from @react-navigation/stack. With that in mind, the Details Stack would be as follows:

    1import React, { useEffect } from "react";
    2import { createStackNavigator } from "@react-navigation/stack";
    3import { getFocusedRouteNameFromRoute } from "@react-navigation/native";
    4import Details from "@screens/Details";
    5import InnerDetails from "@screens/InnerDetails";
    6
    7const screenNames = {
    8  details: "Details",
    9  innerDetails: "InnerDetails",
    10};
    11const DetailsStack = createStackNavigator();
    12
    13function DetailsStackScreen({ navigation, route }) {
    14  const tabHiddenRoutes = ["InnerDetails"];
    15  useEffect(() => {
    16    if (tabHiddenRoutes.includes(getFocusedRouteNameFromRoute(route))) {
    17      navigation.setOptions({ tabBarVisible: false });
    18    } else {
    19      navigation.setOptions({ tabBarVisible: true });
    20    }
    21  }, [navigation, route]);
    22  return (
    23    <DetailsStack.Navigator
    24      headerMode="none"
    25      screenOptions={{
    26        gestureEnabled: true,
    27        gestureDirection: "horizontal",
    28      }}
    29      initialRouteName={screenNames.details}
    30    >
    31      <DetailsStack.Screen name={screenNames.details} component={Details} />
    32      <DetailsStack.Screen
    33        name={screenNames.innerDetails}
    34        component={InnerDetails}
    35      />
    36    </DetailsStack.Navigator>
    37  );
    38}

    Configuring the Tab Bar

    Now we will add the two tabs to the Tab bar. We want the Home screen to be our landing page so we should specify the HomeStack as the initial route in the Tab Navigator.

    It is also possible to add styles to the Tab bar for different orientations using the tabBarOptions property of the Tab Navigator. This can be useful for highlighting the active tab, for example, as we will demonstrate shortly.

    To know more about the props to customize the Tab navigator have a look at https://reactnavigation.org/docs/bottom-tab-navigator/ .

    The Tab bar with the Home and Details tabs would be as follows:

    1import { createBottomTabNavigator } from "@react-navigation/bottom-tabs";
    2
    3const screenNames = {
    4  homeStack: "HomeStackScreen",
    5  detailsStack: "DetailsStackScreen",
    6};
    7const Tab = createBottomTabNavigator();
    8
    9function Navigation() {
    10  return (
    11    <Tab.Navigator
    12      initialRouteName={screenNames.homeStack}
    13      tabBarOptions={{
    14        activeTintColor: "#688E26",
    15        inactiveTintColor: "#6C6C6C",
    16      }}
    17    >
    18      <Tab.Screen
    19        name={screenNames.homeStack}
    20        component={HomeStackScreen}
    21        options={{
    22          tabBarLabel: "",
    23          tabBarIcon: ({ color, focused }) => (
    24            <Icon
    25              name={focused ? "ri-home-fill" : "ri-home-line"}
    26              size="24"
    27              color={color}
    28            />
    29          ),
    30        }}
    31      />
    32      <Tab.Screen
    33        name={screenNames.detailsStack}
    34        component={DetailsStackScreen}
    35        options={{
    36          abBarLabel: "",
    37          tabBarIcon: ({ color, focused }) => (
    38            <Icon
    39              name={focused ? "ri-information-fill" : "ri-information-line"}
    40              size="24"
    41              color={color}
    42            />
    43          ),
    44        }}
    45      />
    46    </Tab.Navigator>
    47  );
    48}

    Putting it all together

    And here is the final Navigation.js code in the Navigation file (src/navigation/Navigation.js):

    1import React, { useEffect } from "react";
    2import { createStackNavigator } from "@react-navigation/stack";
    3import { createBottomTabNavigator } from "@react-navigation/bottom-tabs";
    4import Icon from "react-native-remix-icon";
    5import Home from "@screens/Home";
    6import Details from "@screens/Details";
    7import InnerDetails from "@screens/InnerDetails";
    8import { getFocusedRouteNameFromRoute } from "@react-navigation/native";
    9
    10export const screenNames = {
    11  home: "Home",
    12  details: "Details",
    13  innerDetails: "InnerDetails",
    14  homeStack: "HomeStackScreen",
    15  detailsStack: "DetailsStackScreen",
    16};
    17
    18const HomeStack = createStackNavigator();
    19
    20function HomeStackScreen() {
    21  return (
    22    <HomeStack.Navigator
    23      headerMode="none"
    24      screenOptions={{
    25        gestureEnabled: true,
    26        gestureDirection: "horizontal",
    27      }}
    28      initialRouteName={screenNames.home}
    29    >
    30      <HomeStack.Screen name={screenNames.home} component={Home} />
    31    </HomeStack.Navigator>
    32  );
    33}
    34
    35const DetailsStack = createStackNavigator();
    36
    37function DetailsStackScreen({ navigation, route }) {
    38  const tabHiddenRoutes = ["InnerDetails"];
    39  useEffect(() => {
    40    if (tabHiddenRoutes.includes(getFocusedRouteNameFromRoute(route))) {
    41      navigation.setOptions({ tabBarVisible: false });
    42    } else {
    43      navigation.setOptions({ tabBarVisible: true });
    44    }
    45  }, [navigation, route]);
    46
    47  return (
    48    <DetailsStack.Navigator
    49      headerMode="none"
    50      screenOptions={{
    51        gestureEnabled: true,
    52        gestureDirection: "horizontal",
    53      }}
    54      initialRouteName={screenNames.details}
    55    >
    56      <DetailsStack.Screen name={screenNames.details} component={Details} />
    57      <DetailsStack.Screen
    58        name={screenNames.innerDetails}
    59        component={InnerDetails}
    60      />
    61    </DetailsStack.Navigator>
    62  );
    63}
    64
    65const Tab = createBottomTabNavigator();
    66
    67export default function Navigation() {
    68  return (
    69    <Tab.Navigator
    70      initialRouteName={screenNames.homeStack}
    71      tabBarOptions={{
    72        activeTintColor: "#688E26",
    73        inactiveTintColor: "#6C6C6C",
    74      }}
    75    >
    76      <Tab.Screen
    77        name={screenNames.homeStack}
    78        component={HomeStackScreen}
    79        options={{
    80          tabBarLabel: "",
    81          tabBarIcon: ({ color, focused }) => (
    82            <Icon
    83              name={focused ? "ri-home-fill" : "ri-home-line"}
    84              size="24"
    85              color={color}
    86            />
    87          ),
    88        }}
    89      />
    90      <Tab.Screen
    91        name={screenNames.detailsStack}
    92        component={DetailsStackScreen}
    93        options={{
    94          abBarLabel: "",
    95          tabBarIcon: ({ color, focused }) => (
    96            <Icon
    97              name={focused ? "ri-information-fill" : "ri-information-line"}
    98              size="24"
    99              color={color}
    100            />
    101          ),
    102        }}
    103      />
    104    </Tab.Navigator>
    105  );
    106}

    The following image shows the output: home-details

    Previous
    Next