Tab and Stack Layout in React Native
Tags: javascript, reactnative, tutorial, react
Published: 2022-04-02 03:24:19

I was creating a React Native app with [Expo](https://expo.io) 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:
{% youtube fpnekyzG8LI %}

Code:
{% github https://github.com/ShubhamPatilsd/tab-stack-example %}

![bottom tab navigation with icons to click one](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q3h808mmwbulonaqrjax.png)

I'm going to be using [React Navigation](https://reactnavigation.org/) for this example, as it is the recommended library by Expo to use.

To get started, run (if you use `npm`)
```npm install @react-navigation/native```
or run
```yarn 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";
```
Then, put that component in the your `App()` component:
```jsx
export default function App() {
  return (
    <NavigationContainer>
      {/*It's a surprise tool that'll help us later!*/}
    </NavigationContainer>
  );
}
```

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
```
Installation with `yarn`:
```
yarn add @react-navigation/native-stack
```

Import it with:
```js
import { createNativeStackNavigator } from "@react-navigation/native-stack";
```
Then, create the navigator with (keep it out of any components):
```js
const Stack = createNativeStackNavigator();
```

Then, under our `<NavigationContainer>` component, we add `<Stack.Navigator>` as so:
```jsx
export default function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator>
        {/* TODO: Add screens later */}
      </Stack.Navigator>
    </NavigationContainer>
  );
}
```

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

Let's create two screens, `Main` and `Settings`. Put:
```jsx
<Stack.Screen name="Main" component={Main}/>
<Stack.Screen name="Settings" component={Settings} />
```
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
```jsx
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>;
}
```

The styles are the default template styles we're given when creating an Expo app, but if you need them here they are:
```jsx
const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "#fff",
    alignItems: "center",
    justifyContent: "center",
  },
});
```

Now, your `App.js`/`App.tsx` should look like this:
```jsx
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",
  },
});
```

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

Installation with `npm`:
```
npm install @react-navigation/bottom-tabs
```
Installation with `yarn`:
```
yarn add @react-navigation/bottom-tabs
```

Import it with
```jsx
import { createBottomTabNavigator } from "@react-navigation/bottom-tabs";
```

and add 
```jsx
const Tab = createBottomTabNavigator();
```
below the `Stack` definition:

```js
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
```
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.

```jsx
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>
  );
}
```
The `Tab.Navigator` contains screens that we can navigate to with the bottom tab bar that shows up. 

Here is the code so far:
```jsx
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",
  },
});
```

Now, go to the `Main` function and add a `navigator` parameter to the function's parameters like so:
```js
function Main({navigation}){
    /*...*/
}
```

Then, go to the `Tab.Screen` called "Home", and change it to
```jsx
 <Tab.Screen
        name="Home"
        component={() => {
          return (
            <View>
              <Text>Home Screen</Text>
              <Button
                onPress={() => {
                  navigation.navigate("Settings");
                }}
                title="Go to settings"
              />
            </View>
          );
        }}
        options={{
          headerShown: false,
        }}
      />
```

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:
{% youtube fpnekyzG8LI %}

This is the entire code:
```jsx
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",
  },
});
```

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

In the mean time, follow me on [Twitter](https://twitter.com/ShubhamPatilsd) to get more frequent updates on my coding journey!
👋