DEV Community

Cover image for Tab and Stack Layout in React Native
Shubham Patil
Shubham Patil

Posted on

Tab and Stack Layout in React Native

I was creating a React Native app with Expo a week ago and I had to do a layout with a bottom tab navigator and implement a stack layout at the same time. Stack navigation essentially puts screens on top of other screens when you navigate to other pages, while tab navigation allows you to have a bottom page to choose between pages.

Here is the demo:

Code:

GitHub logo ShubhamPatilsd / tab-stack-example

React Native Tab Stack Example

bottom tab navigation with icons to click one

I'm going to be using React Navigation for this example, as it is the recommended library by Expo to use.

To get started, run (if you use npm)


 install @react-navigation/native

Enter fullscreen mode Exit fullscreen mode

or run


 add @react-navigation/native

``` if you use Yarn to get started.

I prefer `yarn` so I chose that one.

Next, if you're using Expo, run
```expo

 install react-native-screens react-native-safe-area-context

``` to install the required dependencies for the project.

There is additional setup for base React Native projects, like pod linking and those additional dependencies, so check out the full setup guide [here](https://reactnavigation.org/docs/getting-started/).

Next, open up your `App.js` or `App.tsx` and import `NavigationContainer` from the React Navigation Library.

Import it by using
```js


import { NavigationContainer } from "@react-navigation/native";


Enter fullscreen mode Exit fullscreen mode

Then, put that component in the your App() component:



export default function App() {
  return (
    <NavigationContainer>
      {/*It's a surprise tool that'll help us later!*/}
    </NavigationContainer>
  );
}


Enter fullscreen mode Exit fullscreen mode

Now, we need to implement the Stack screen navigator.

We are going to import a function that gives us a navigator we can use to wrap all our screens in.

To install the stack navigator, we need an npm package called @react-navigation/native-stack. (Yes, another package 🙄).

Installation with npm:



npm install @react-navigation/native-stack


Enter fullscreen mode Exit fullscreen mode

Installation with yarn:



yarn add @react-navigation/native-stack


Enter fullscreen mode Exit fullscreen mode

Import it with:



import { createNativeStackNavigator } from "@react-navigation/native-stack";


Enter fullscreen mode Exit fullscreen mode

Then, create the navigator with (keep it out of any components):



const Stack = createNativeStackNavigator();


Enter fullscreen mode Exit fullscreen mode

Then, under our <NavigationContainer> component, we add <Stack.Navigator> as so:



export default function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator>
        {/* TODO: Add screens later */}
      </Stack.Navigator>
    </NavigationContainer>
  );
}


Enter fullscreen mode Exit fullscreen mode

And next, as you guessed, we're going to add screens.

Let's create two screens, Main and Settings. Put:



<Stack.Screen name="Main" component={Main}/>
<Stack.Screen name="Settings" component={Settings} />


Enter fullscreen mode Exit fullscreen mode

under <Stack.Navigator>.

Oh no! You don't have a Main/Settings component? Don't worry, we can make one really quickly.

Outside of any of our other components (you can put it inside but I like it outside), create the Main component with



function Main() {
  return <Text style={styles.container}>I ❤ React Native</Text>;
}

function Settings() {
  return <Text style={styles.container}>You got to the settings page</Text>;
}


Enter fullscreen mode Exit fullscreen mode

The styles are the default template styles we're given when creating an Expo app, but if you need them here they are:



const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "#fff",
    alignItems: "center",
    justifyContent: "center",
  },
});


Enter fullscreen mode Exit fullscreen mode

Now, your App.js/App.tsx should look like this:



import { StyleSheet, Text } from "react-native";
import * as React from "react";
import { NavigationContainer } from "@react-navigation/native";
import { createNativeStackNavigator } from "@react-navigation/native-stack";

const Stack = createNativeStackNavigator();

function Main() {
  return <Text style={styles.container}>I ❤ React Native</Text>;
}

function Settings() {
  return <Text style={styles.container}>You got to the settings page</Text>;
}

export default function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator>
        <Stack.Screen name="Main" component={Main} />
        <Stack.Screen name="Settings" component={Settings} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "#fff",
    alignItems: "center",
    justifyContent: "center",
  },
});


Enter fullscreen mode Exit fullscreen mode

Okay, now let's add a tab navigator into the mix. Time for more packages 🥳 📦!

Installation with npm:



npm install @react-navigation/bottom-tabs


Enter fullscreen mode Exit fullscreen mode

Installation with yarn:



yarn add @react-navigation/bottom-tabs


Enter fullscreen mode Exit fullscreen mode

Import it with



import { createBottomTabNavigator } from "@react-navigation/bottom-tabs";


Enter fullscreen mode Exit fullscreen mode

and add



const Tab = createBottomTabNavigator();


Enter fullscreen mode Exit fullscreen mode

below the Stack definition:



import { NavigationContainer } from "@react-navigation/native";
import { createNativeStackNavigator } from "@react-navigation/native-stack";
import { createBottomTabNavigator } from "@react-navigation/bottom-tabs";

const Stack = createNativeStackNavigator();
const Tab = createBottomTabNavigator(); //this one


Enter fullscreen mode Exit fullscreen mode

Now, let's go to the Main component. You want to change it so that it has a Tab navigator, so that we can have tab-based navigation.



function Main() {
  return (
    <Tab.Navigator
      screenOptions={{
        tabBarActiveTintColor: "#0d9f61",
      }}
    >
      <Tab.Screen
        name="Home"
        component={() => {
          return (
            <View>
              <Text>Home Screen</Text>
            </View>
          );
        }}
        options={{
          headerShown: false,
        }}
      />

      <Tab.Screen
        name="OtherPage"
        component={() => {
          return <Text>Other Screen</Text>;
        }}
        options={{
          headerShown: false,
        }}
      />
    </Tab.Navigator>
  );
}


Enter fullscreen mode Exit fullscreen mode

The Tab.Navigator contains screens that we can navigate to with the bottom tab bar that shows up.

Here is the code so far:



import { Button, StyleSheet, Text, View } from "react-native";
import * as React from "react";
import { NavigationContainer } from "@react-navigation/native";
import { createNativeStackNavigator } from "@react-navigation/native-stack";
import { createBottomTabNavigator } from "@react-navigation/bottom-tabs";

const Stack = createNativeStackNavigator();
const Tab = createBottomTabNavigator();

function Main() {
  return (
    <Tab.Navigator
      screenOptions={{
        tabBarActiveTintColor: "#0d9f61",
      }}
    >
      <Tab.Screen
        name="Home"
        component={() => {
          return (
            <View>
              <Text>Home Screen</Text>
            </View>
          );
        }}
        options={{
          headerShown: false,
        }}
      />

      <Tab.Screen
        name="OtherPage"
        component={() => {
          return <Text>Other Screen</Text>;
        }}
        options={{
          headerShown: false,
        }}
      />
    </Tab.Navigator>
  );
}

function Settings() {
  return <Text style={styles.container}>You got to the settings page</Text>;
}

export default function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator>
        <Stack.Screen name="Main" component={Main} />
        <Stack.Screen name="Settings" component={Settings} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "#fff",
    alignItems: "center",
    justifyContent: "center",
  },
});


Enter fullscreen mode Exit fullscreen mode

Now, go to the Main function and add a navigator parameter to the function's parameters like so:



function Main({navigation}){
    /*...*/
}


Enter fullscreen mode Exit fullscreen mode

Then, go to the Tab.Screen called "Home", and change it to



 <Tab.Screen
        name="Home"
        component={() => {
          return (
            <View>
              <Text>Home Screen</Text>
              <Button
                onPress={() => {
                  navigation.navigate("Settings");
                }}
                title="Go to settings"
              />
            </View>
          );
        }}
        options={{
          headerShown: false,
        }}
      />


Enter fullscreen mode Exit fullscreen mode

Here, we added a button, so that we can go back to the Settings page. The onPress with navigation.navigate does the action of going to the "Settings" page when pressed.

And there you have it!

Here is the demo:

This is the entire code:



import { Button, StyleSheet, Text, View } from "react-native";
import * as React from "react";
import { NavigationContainer } from "@react-navigation/native";
import { createNativeStackNavigator } from "@react-navigation/native-stack";
import { createBottomTabNavigator } from "@react-navigation/bottom-tabs";

const Stack = createNativeStackNavigator();
const Tab = createBottomTabNavigator();

function Main({ navigation }) {
  return (
    <Tab.Navigator
      screenOptions={{
        tabBarActiveTintColor: "#0d9f61",
      }}
    >
      <Tab.Screen
        name="Home"
        component={() => {
          return (
            <View>
              <Text>Home Screen</Text>
              <Button
                onPress={() => {
                  navigation.navigate("Settings");
                }}
                title="Go to settings"
              />
            </View>
          );
        }}
        options={{
          headerShown: false,
        }}
      />

      <Tab.Screen
        name="OtherPage"
        component={() => {
          return <Text>Other Screen</Text>;
        }}
        options={{
          headerShown: false,
        }}
      />
    </Tab.Navigator>
  );
}

function Settings() {
  return <Text style={styles.container}>You got to the settings page</Text>;
}

export default function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator>
        <Stack.Screen name="Main" component={Main} />
        <Stack.Screen name="Settings" component={Settings} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "#fff",
    alignItems: "center",
    justifyContent: "center",
  },
});


Enter fullscreen mode Exit fullscreen mode

Hope this helps and I'll come back in a couple of weeks with more stuff!

In the mean time, follow me on Twitter to get more frequent updates on my coding journey!
👋

Top comments (0)