Skip to content

Navigation Re-imagined: Mastering Expo Router - The Basics

Posted on:April 28, 2025

Welcome back, Developer! 👋

In our previous adventure, we built the foundation for Student Mate—a simple app for university students—using React Native, Expo, and TypeScript. Today, let’s continue that journey by setting up clean, scalable navigation using Expo Router.

If you’re tired of writing boilerplate for navigation setups, you’re going to love how Expo Router makes routing elegant, intuitive, and file-system based!


Table of contents

Open Table of contents

Why Expo Router for Student Mate?

With Expo Router, you get:

In short: less code, more features. Let’s dive in!


Setting things up

For a quick start, make sure you have the Student Mate GitHub repository cloned and ready. You need to check out the branch post/data-persistence-react-native-expo. We’ll be building directly on top of it.

If you haven’t yet installed required packages:

cd student-mate
npm install

How Tab Navigation Works

Tab navigation is defined inside app/(tabs)/_layout.tsx using the <Tabs> component from Expo Router. Let’s replace its content with:

// app/(tabs)/_layout.tsx
import { Tabs } from "expo-router";
 
export default function TabLayout() {
  return (
    <Tabs>
      <Tabs.Screen name="index" options={{ title: "Home" }} />
      <Tabs.Screen name="classes" options={{ title: "Classes" }} />
      <Tabs.Screen name="assignments" options={{ title: "Assignments" }} />
      <Tabs.Screen name="profile" options={{ title: "Profile" }} />
    </Tabs>
  );
}

Each <Tabs.Screen> automatically matches a screen file inside the (tabs) folder:

No need to manually register routes — Expo Router figures it out!


Creating Pages for Classes, Assignments, and Profile

Now let’s create the three main screens for our app: Classes, Assignments, and Profile.

Create a file for each screen inside the (tabs) folder:

1. Classes Page

// app/(tabs)/classes.tsx
import { View, Text, StyleSheet } from "react-native";
 
export default function ClassesScreen() {
  return (
    <View style={styles.container}>
      <Text style={styles.title}>Your Class Schedule 📚</Text>
    </View>
  );
}
 
const styles = StyleSheet.create({
  container: { flex: 1, justifyContent: "center", alignItems: "center" },
  title: { fontSize: 24, color: "grey" },
});

The Classes page will later be expanded to list all of a student’s enrolled classes.

2. Assignments Page

// app/(tabs)/assignments.tsx
import { View, Text, StyleSheet, Pressable } from "react-native";
import { router } from "expo-router";
 
const assignments = [
  { id: "1", title: "Math Homework" },
  { id: "2", title: "Science Project" },
  { id: "3", title: "History Essay" },
];
 
export default function AssignmentsScreen() {
  return (
    <View style={styles.container}>
      <Text style={styles.title}>Upcoming Assignments 📑</Text>
 
      {assignments.map((assignment) => (
        <Pressable
          key={assignment.id}
          style={styles.item}
          onPress={() => router.push(`/assignments/${assignment.id}`)}
        >
          <Text style={styles.itemText}>{assignment.title}</Text>
        </Pressable>
      ))}
    </View>
  );
}
 
const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: "center",
    alignItems: "center",
    padding: 20,
  },
  title: { fontSize: 24, marginBottom: 20, color: "grey" },
  item: {
    marginVertical: 10,
    padding: 10,
    backgroundColor: "grey",
    width: "100%",
    borderRadius: 8,
  },
  itemText: { fontSize: 18, color: "blue" },
});

The Assignments page will later allow us to list and manage tasks for the student.

3. Profile Page

// app/(tabs)/profile.tsx
import { View, Text, StyleSheet } from "react-native";
 
export default function ProfileScreen() {
  return (
    <View style={styles.container}>
      <Text style={styles.title}>Your Profile 👤</Text>
    </View>
  );
}
 
const styles = StyleSheet.create({
  container: { flex: 1, justifyContent: "center", alignItems: "center" },
  title: { fontSize: 24, color: "grey" },
});

The Profile page will display user-specific information like name, email, and settings.

Each screen now appears as a tab in your app, thanks to the automatic linking by Expo Router.


Creating a Home (Dashboard) Screen

Let’s update app/(tabs)/index.tsx with a basic dashboard:

// app/(tabs)/index.tsx
import { Link } from "expo-router";
import { View, Text, StyleSheet } from "react-native";
 
export default function HomeScreen() {
  return (
    <View style={styles.container}>
      <Text style={styles.title}>Welcome to Student Mate 🎓</Text>
 
      <Link href="/classes" style={styles.link}>
        View Your Classes
      </Link>
      <Link href="/assignments" style={styles.link}>
        View Assignments
      </Link>
      <Link href="/profile" style={styles.link}>
        Go to Profile
      </Link>
    </View>
  );
}
 
const styles = StyleSheet.create({
  container: { flex: 1, justifyContent: "center", alignItems: "center" },
  title: { fontSize: 24, marginBottom: 20, color: "grey" },
  link: { marginTop: 10, color: "blue" },
});

Try it out

Great, we’re doing very well so far! Let’s give it a go, Developer?

npm start

Scan the QR with your device to open the App with Expo Go (same as we saw in the previous post).

You should be able to click on each of the links on the Dashboard page and be redirected to the respective page (not the best UI style I know!).

Dynamic Routes Example: Assignment Details

To illustrate a real world scenario, let’s learn how to implement a dynamic route. We want students to tap on an assignment and see more info. Let’s add dynamic routing.

First, create a folder:

app/
└── assignments/
    └── [id].tsx

Here’s the dynamic assignment screen:

// app/assignments/[id].tsx
import { useLocalSearchParams } from "expo-router";
import { View, Text, StyleSheet } from "react-native";
 
export default function AssignmentDetail() {
  const { id } = useLocalSearchParams();
 
  return (
    <View style={styles.container}>
      <Text style={styles.title}>Assignment Details</Text>
      <Text>Assignment ID: {id}</Text>
    </View>
  );
}
 
const styles = StyleSheet.create({
  container: { flex: 1, justifyContent: "center", alignItems: "center" },
  title: { fontSize: 22, marginBottom: 10 },
});

To test it, just go to the Assignments page and choose one of the options!


What We Learned in Part 1

  1. How Expo Router uses file structure to generate navigation automatically.
  2. How to set up tabs with zero boilerplate.
  3. How to create dynamic routes (like assignment detail pages).
  4. How to build real-world screens for classes, assignments, and profiles.

What’s Next

In Part 2, we’ll dive deeper:

See you in the next one, Developer. Enjoy the journey and have fun! 💙