Expo Router Tab Navigation -From the Docs
Tags: reactnative, expo, react, tutorial
Published: 2023-07-24 16:50:43

### Overview
Welcome to the second installment of my [Expo Router](https://docs.expo.dev/routing/installation/#manual-installation) file-based routing video series! In this series, I will be diving into various aspects of Expo Router, including basic routing, dynamic routes, and the Tab Navigator.

As I delved into working with the new router, I initially started with the basic two-tab template, which has been a valuable starting point. However, there were instances where I found myself puzzled by the magic happening behind the scenes.

To address this, I decided to take a step back and [create these videos](https://www.youtube.com/playlist?list=PL2PY2-9rsgl3fgR9Nh4Ee_U2xyb3RLhQd) from scratch. Together, we will add Expo Router to a basic Expo application and follow the documentation closely as we build the application. Along the way, I'll be sharing all the steps I take in detail, as I felt the existing documentation on using the Tab Navigator from scratch wasn't very clear, in my honest opinion.

{% youtube ZCj85YJZF04 %}

I'm excited about this journey, and I hope you'll join me as we explore Expo Router and its functionalities. Feel free to share this content with your friends and associates as well—let's learn and grow together!

### The Steps

Run this command to build the app project
```jsx
npx create-expo-app@latest --template blank@sdk-49  my-app-tabs-expo-router
```

Change into the project directory and install the additional dependencies

```jsx
npx expo install expo-router@latest react-native-safe-area-context react-native-screens expo-linking expo-constants expo-status-bar react-native-gesture-handler
```

Open the `package.json` file and make the following update

```jsx
{
  "main": "expo-router/entry"
}
```

Not using web so skipping that part of documentation, but add the scheme `app.json`

```jsx
"scheme": "myapptabsexporouter",
```

update `babel.config.js` to include the new plugin.

```jsx
module.exports = function (api) {
  api.cache(true);
  return {
    presets: ['babel-preset-expo'],
    plugins: ['expo-router/babel'],
  };
};
```

Lets add the index page and then test it is working, remember the files all live in a new app directory that you have to create. `/app/index.js`

```jsx
// /app/index.js

import { Text } from 'react-native';

export default function Page() {
  return <Text>Home page</Text>;
}
```

lets add a group for tabs by creating a folder with the folder name "tabs" in parenthesis, `/app/(tabs)`

```jsx
(tabs)
```

then add a new _layout.js file in the "(tabs)" folder. The directory should look like this `/app/(tabs)/_layout.js`. We are adding the Tabs UI component and adding one Tab called "Home".

```jsx
import { Tabs } from "expo-router";

export default function TabsLayout() {
  return (
    <Tabs screenOptions={{ headerShown: false }}>
      <Tabs.Screen
        name="home"
        options={{
          tabBarLabel: "Home",
          title: "Home"
        }}
      />
    </Tabs>
  );
}
```

Create a new folder name "home" and add an `index.js` to that folder. The new file will be the index page of the Home tab stack. The directory should look like this `/app/(tabs)/home/index.js`

```jsx
// /app/(tabs)/home/index.js

import { Text } from 'react-native';

export default function Page() {
  return <Text>Index page of Home Tab</Text>;
}
```

But we need a layout for the home folder, so add a new file with the contents below. `/app/(tabs)/home/_layout.js`

```jsx
// /app/(tabs)/home/_layout.js

import { Stack } from "expo-router";

export default function HomeLayout() {
  return <Stack />;
}
```

Now we need to update the `/app/index.js` to redirect to the `/app/(tabs)/home` at start up.

```jsx
// /app/index.js

import { Redirect } from 'expo-router';
import { Text } from 'react-native';

export default function Page() {
  return <Redirect href={"/(tabs)/home"} />;
}
```

We then repeat the process for the second tab called "Settings", first update the `_layout.js` in the tabs group/folder to include the second tab. It will be called settings `/app/(tabs)/_layout.js`

```jsx
// /app/(tabs)/_layout.js

import { Tabs } from "expo-router";

export default function TabsLayout() {
  return (
    <Tabs screenOptions={{ headerShown: false }}>
      <Tabs.Screen
        name="home"
        options={{
          tabBarLabel: "Home",
          title: "Home",
        }}
      />
      <Tabs.Screen
        name="settings"
        options={{
          tabBarLabel: "Settings",
          title: "Settings",
        }}
      />
    </Tabs>
  );
}
```

To make things easier, just copy the `home` folder and rename the new copy to `settings`, then edit the `index.js` file in the `settings` folder with the following code.

```jsx
// /app/(tabs)/settings/index.js

import { Text } from 'react-native';

export default function Page() {
  return <Text>Index page of Settings Tab</Text>;
}
```

At this point you should have the basic two tabs app running


### Some Extras

Now lets fix the page titles, first the Settings. Add a `Stack.Screen` element and set the `options`

```jsx
// /app/(tabs)/settings/index.js

import { Stack } from "expo-router";
import { Text, View } from "react-native";

export default function Page() {
  return (
    <View>
      <Stack.Screen options={{ headerShown: true, title: "Settings" }} />
      <Text>Index page of Settings Tab</Text>
    </View>
  );
}
```

Then the Home

```jsx
// /app/(tabs)/home/index.js

import { Stack } from "expo-router";
import { Text, View } from "react-native";

export default function Page() {
  return (
    <View>
      <Stack.Screen options={{ headerShown: true, title: "Home" }} />
      <Text>Index page of Home Tab</Text>
    </View>
  );
}
```

Now lets show some nested navigation in the Home Tab, add a link to a new page,  `/app/(tabs)/settings/index.js` which when clicked with navigate to the new page `next-page`

```jsx
// /app/(tabs)/home/index.js

export default function Page() {
  return (
    <View>
      <Stack.Screen options={{ headerShown: true, title: "Home" }} />
      <Text>Index page of Home Tab</Text>
      <Link href={"/home/next-page"} style={{ marginTop: 16 }}>
        <Text style={{ fontWeight: "bold" }}>Go To Next Page</Text>
      </Link>
    </View>
  );
}
```

Create the new page `next-page.js` in the Home folder

```jsx
// /app/(tabs)/home/next-page.js

import { Stack } from "expo-router";
import { Text, View } from "react-native";

export default function NextPage() {
  return (
    <View>
      <Stack.Screen options={{ headerShown: true, title: "Next Page" }} />
      <Text>Next page of Home Tab</Text>
    </View>
  );
}
```

Lets add some icons to our tab buttons; import the icons in the `/(tabs)/_layout.js` file

```jsx
// /app/(tabs)/_layout.js

import FontAwesome from "@expo/vector-icons/FontAwesome";
```

Then for the home tab icon, make the following change to the `Tab.Screen` for the Home, add this as a new option `/(tabs)/_layout.js`

```jsx
// /app/(tabs)/_layout.js

   tabBarIcon: ({ color }) => (
      <FontAwesome
        size={28}
        style={{ marginBottom: -3 }}
        name="home"
        color={color}
      />
    ),

```

Then do the same for the Settings, but change the name of the icon from “home” to “gear” , add this as a new option

```jsx
// /app/(tabs)/_layout.js

tabBarIcon: ({ color }) => (
  <FontAwesome
    size={28}
    style={{ marginBottom: -3 }}
    name="home"
    color={color}
  />
),
```

When you are done the layout should look like this

```jsx
// /app/(tabs)/_layout.js

import { Tabs } from "expo-router";
import FontAwesome from "@expo/vector-icons/FontAwesome";

export default function TabsLayout() {
  return (
    <Tabs screenOptions={{ headerShown: false }}>
      <Tabs.Screen
        name="home"
        options={{
          tabBarLabel: "Home",
          title: "Home",
          tabBarIcon: ({ color }) => (
            <FontAwesome
              size={28}
              style={{ marginBottom: -3 }}
              name="home"
              color={color}
            />
          ),
        }}
      />
      <Tabs.Screen
        name="settings"
        options={{
          tabBarLabel: "Settings",
          title: "Settings",
          tabBarIcon: ({ color }) => (
            <FontAwesome
              size={28}
              style={{ marginBottom: -3 }}
              name="gear"
              color={color}
            />
          ),
        }}
      />
    </Tabs>
  );
}
```

## Wrap
Well I hope you found this helpful, I think it is a bit more detailed than what the documentation provided and it can also be beneficial to those looking for something without typescript.

### Links
- Expo Router Doc - https://docs.expo.dev/routing/installation/#manual-installation
- Stack Navigation Video - https://youtu.be/wBjy08dxL8I


### Social Media 
YouTube - https://www.youtube.com/@AaronSaundersCI
Twitter - https://twitter.com/aaronksaunders
Facebook - https://www.facebook.com/ClearlyInnovativeInc
Instagram - https://www.instagram.com/aaronksaunders/
Dev.to - https://dev.to/aaronksaunders