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:
- 🚀 Automatic routing based on your folder structure
- 🔥 Seamless deep linking and web URL support
- ✨ Native-feeling tabs, stacks, and modals — without messy config
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:
index.tsx
→ Homeclasses.tsx
→ Class scheduleassignments.tsx
→ Assignmentsprofile.tsx
→ Profile
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" },
});
<Link href="/classes" />
handles navigation — no manual button logic needed.- Clean, simple, and powerful. ✨
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 },
});
useLocalSearchParams()
pulls the assignment ID from the URL.- Now
/assignments/123
will dynamically render assignment 123!
To test it, just go to the Assignments page and choose one of the options!
What We Learned in Part 1
- How Expo Router uses file structure to generate navigation automatically.
- How to set up tabs with zero boilerplate.
- How to create dynamic routes (like assignment detail pages).
- How to build real-world screens for classes, assignments, and profiles.
What’s Next
In Part 2, we’ll dive deeper:
- Stack navigation inside tabs
- Modal screens (for quick actions like adding an assignment)
- Route groups for organization (like
(auth)
and(modals)
)
See you in the next one, Developer. Enjoy the journey and have fun! 💙