Welcome to the Part 2 of Navigation Re-imagined: Mastering Expo Router, Developer đź‘‹
If you missed it, in Part 1 we covered:
- 🚀 Fast tab navigation setup
- đź”— Real app screens (Classes, Assignments, Profile)
- ⚡️ Dynamic routes for assignment details
Navigation can feel like solving a maze, but with Expo Router it becomes more like following clear signposts. In this part, we’ll add stacks, modals, and route groups, and explain every piece so that even non-technical readers can follow along.
Let’s continue our journey to make navigation simple and understandable!
Table of Contents
Open Table of Contents
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/navigation-expo-router-part-1. We’ll be building directly on top of it.
If you haven’t yet installed required packages:
cd student-mate
npm install
Stack Navigation Inside Tabs
What is Expo Router’s Stack feature?
A Stack is like a deck of cards: you place new screens on top and pop them off to go back. This pattern is great for drilling into details while keeping your tab context intact.
Think of your app as a book, developer. Tabs are the main chapters (like “Classes”), and stacks are the pages inside those chapters. You open a chapter (tab) and flip pages (stack screens) to see more details.
Does that make sense? Allow me to show you.
Folder Structure
app/
└── (tabs)/
└── classes/
├── _layout.tsx # Defines how the pages inside "Classes" work together
├── index.tsx # The main Classes list
└── [classId].tsx # A detail page for a specific class
- (tabs)/classes/_layout.tsx: Think of this as the table of contents for the Classes chapter.
Creating the Layout File
- Create the file
app/(tabs)/classes/_layout.tsx
. - Import the Stack component.
- Define your screens inside
.
// app/(tabs)/classes/_layout.tsx
import { Stack } from 'expo-router';
/**
* ClassesLayout sets up a Stack navigator:
* - index.tsx shows the list of classes.
* - [classId].tsx shows details for one class.
*/
export default function ClassesLayout() {
return (
<Stack
screenOptions={{
headerStyle: { backgroundColor: '#f0f0f0' },
headerTintColor: '#333',
}}
>
{/* Main list of classes */}
<Stack.Screen
name="index"
options={{ title: 'Your Classes' }}
/>
{/* Detail page for a selected class */}
<Stack.Screen
name="[classId]"
options={({ route }) => ({
title: `Class ${route.params.classId}`,
})}
/>
</Stack>
);
}
How it works
<Stack>
: Think of this as our stack of pages.screenOptions
: Sets a default look (header background & text color).<Stack.Screen name="index" />
: Connects toindex.tsx
.<Stack.Screen name="[classId]" />
: Connects to[classId].tsx
, using the URL parameter to show which class.
Modal Screens
What is a Modal in Expo Router?
Imagine a pop‑up window that floats above your book. That’s a modal — great for quick tasks like adding a new assignment without tearing the reader away from the main content.
Expo Router adds modal support via a special route group: any folder named with parentheses and containing a .tsx file will open as a modal overlay.
Create the Modals Folder
app/
└── (modals)/
└── add-assignment.tsx # The Add Assignment pop‑up
Modal Component
// app/(modals)/add-assignment.tsx
import { View, Text, TextInput, Button, StyleSheet } from 'react-native';
import { router } from 'expo-router';
/**
* AddAssignmentModal:
* - Overlay screen for adding a new assignment.
* - Part of the navigation flow (not just a UI popup).
*/
export default function AddAssignmentModal() {
return (
<View style={styles.modal}>
<Text style={styles.title}>âž• Add New Assignment</Text>
<TextInput placeholder="Title" style={styles.input} />
<TextInput placeholder="Due Date" style={styles.input} />
<Button
title="Save & Close"
onPress={() => router.back()} // Closes the modal
/>
</View>
);
}
const styles = StyleSheet.create({
modal: {
flex: 1,
justifyContent: 'center',
backgroundColor: 'rgba(0,0,0,0.5)', // Semi-transparent backdrop
padding: 20,
},
title: { fontSize: 24, color: '#fff', marginBottom: 20 },
input: {
backgroundColor: '#fff',
padding: 10,
marginBottom: 15,
borderRadius: 6,
},
});
Let’s break it down
<View style={styles.modal}>
: The big box covering the screen.router.back()
: Think of this as saying “close the pop‑up and go back.”
How to Open the Modal
In app/(tabs)/assignments.tsx
, add:
<Button
title="Add Assignment"
onPress={() => router.push('/add-assignment')} // Opens our modal
/>
Then start your app:
npm run start
Route Groups for Organization
What are Route Groups?
Route groups let you organize related screens without changing the URL structure—useful for auth flows, overlays, or shared routes. For example, like grouping all login pages in a secret folder.
Auth Flow Example
app/
├── (auth)/
│ ├── login.tsx # Sign-in screen
│ └── register.tsx # Sign-up screen
└── ...
On the app/(auth)/login.tsx
file:
import { View, Text, Button, StyleSheet } from 'react-native';
import { router } from 'expo-router';
export default function Login() {
return (
<View style={styles.container}>
<Text style={styles.title}>đź”’ Login to Student Mate</Text>
<Button
title="Go to Register"
onPress={() => router.push('/register')}
/>
</View>
);
}
const styles = StyleSheet.create({
container: { flex: 1, justifyContent: 'center', alignItems: 'center' },
title: { fontSize: 24, marginBottom: 20 },
});
On the row 10 highlighted, check how the router is redirecting to /register
without the need of the (auth)
route group.
What We Learned in Part 2
- Stacks in Tabs: Like pages inside chapters—gives depth without losing the main tab.
- Modals: Floating panels for quick tasks—open with
router.push
, close withrouter.back
. - Route Groups: Invisible folders for organizing code—no impact on URLs.
What’s Next
In Part 3, we’ll learn how to:
- Integrate Authentication with React Context for real users
- Set up Deep Linking so other apps can launch specific screens
- Apply Theming for a consistent look and feel
The journey of a thousand miles begins with a single step. – Lao Tzu
Keep exploring, stay curious, and happy coding! đź’™