React Nested Routes
Table of Contents + −
In the last lesson, React Route Parameters, one route handled many URLs. This lesson is about nested routes, where child pages live inside a parent and share its layout.
🤔 Why do we need nested routes?
Here’s the pain. A whole section of your app shares a common frame, and you don’t want to repeat it on every sub-page.
- A dashboard has a sidebar on every one of its pages: Overview, Reports, Settings.
- Without nesting, you’d copy that sidebar into each page component.
- The URLs are related too, like
/dashboard,/dashboard/reports,/dashboard/settings. - You want the shared frame written once, with just the inside swapping.
So nested routes fix this. The parent route holds the shared layout, and child routes fill in the changing part.
🧩 Nesting Route inside Route
You nest by putting Route elements inside another Route. The outer one is the parent layout; the inner ones are the children.
import { Routes, Route } from "react-router-dom";
function App() { return ( <Routes> <Route path="/dashboard" element={<DashboardLayout />}> <Route path="overview" element={<Overview />} /> <Route path="reports" element={<Reports />} /> <Route path="settings" element={<Settings />} /> </Route> </Routes> );}Read the structure top to bottom.
- The parent
Routehaspath="/dashboard"and a layout component,DashboardLayout. - The child
Routes sit inside it, with shorter paths likeoverview(no leading slash). - Child paths join onto the parent, so
overviewbecomes/dashboard/overview. - So
/dashboard/reportsshows theDashboardLayoutwithReportsinside it.
Child paths are relative
Notice the children use reports, not /reports. They build on top of the parent path. So reports under /dashboard makes the full URL /dashboard/reports. No leading slash on children.
🔌 The Outlet: where the child shows up
Here’s the key piece. The parent layout needs to say where the child should appear. You do that with the Outlet component.
import { Outlet } from "react-router-dom";
function DashboardLayout() { return ( <div className="dashboard"> <aside>Sidebar: links to Overview, Reports, Settings</aside>
<main> <Outlet /> {/* the matching child route renders right here */} </main> </div> );}So think of Outlet as the hole in the frame, here’s what it does.
Outletis a placeholder inside the parent layout.- Whichever child route matches the URL gets rendered exactly where
Outletsits. - So the sidebar stays the same, and only the
Outletspot changes between Overview, Reports, and Settings. - Without an
Outlet, the child has nowhere to appear, so you’d just see the layout with an empty middle.
No Outlet, no child
If you forget <Outlet /> in the parent layout, the child routes match but render nothing visible. The layout shows, but the changing part stays empty. The Outlet is what makes nesting actually display.
🏠 An index route for the default child
What should show at /dashboard itself, with no child path? You use an index route, the default child for the parent’s exact path.
<Route path="/dashboard" element={<DashboardLayout />}> <Route index element={<Overview />} /> {/* shows at /dashboard */} <Route path="reports" element={<Reports />} /> <Route path="settings" element={<Settings />} /></Route>Here’s what the index route does.
index(instead of apath) means “this is the default child for the parent’s path”.- So visiting
/dashboardexactly showsOverviewin theOutlet. - It’s the landing content for the section, so the user sees something without going to
/dashboard/overview.
⚠️ Common Mistakes
The biggest mistake is forgetting the Outlet, so children never appear.
// ❌ parent layout with no Outlet - children match but show nothingfunction DashboardLayout() { return <div><aside>Sidebar</aside></div>;}
// ✅ add the Outlet where children should renderfunction DashboardLayout() { return <div><aside>Sidebar</aside><Outlet /></div>;}Keep these in mind.
- Don’t forget
<Outlet />in the parent, or children render nowhere. - Don’t put a leading slash on child paths. Use
reports, not/reports. - Don’t repeat the shared layout in each child. That’s the whole thing nesting removes.
✅ Best Practices
A few habits for nested routes.
- Use nesting when a group of pages shares a common layout, like a dashboard or settings area.
- Put the shared frame in the parent’s layout component, with
<Outlet />where children go. - Keep child paths relative (no leading slash), so they build on the parent path.
- Add an
indexroute for the default content at the parent’s exact path.
Nesting can go deeper
A child route can itself have children, nesting as deep as your app needs. Start with one level, like a dashboard with sub-pages. The same Outlet idea works at every level.
🧩 What You’ve Learned
- ✅ Nested routes let child pages share a parent’s layout, written once
- ✅ Nest by putting
Routeelements inside anotherRoute - ✅ Child paths are relative, so
reportsunder/dashboardbecomes/dashboard/reports - ✅ The parent layout uses
<Outlet />to mark where the matching child renders - ✅ Without an
Outlet, children match but show nothing - ✅ An
indexroute sets the default child shown at the parent’s exact path
Check Your Knowledge
Test what you learned. Pick an answer for each question, then click Check.
- 1
What are nested routes used for?
Why: Nested routes let child pages reuse a parent's layout, like a dashboard sidebar, while only the inner part changes between sub-pages.
- 2
What does the Outlet component do?
Why: Outlet is a placeholder in the parent layout. The matching child route renders exactly where the Outlet sits, while the rest of the layout stays put.
- 3
How should you write child route paths?
Why: Child paths are relative and build on the parent. Under /dashboard, a child path of reports makes the full URL /dashboard/reports.
- 4
What is an index route?
Why: An index route (written with index instead of a path) is the default child. It fills the Outlet when the user is on the parent path with no child selected.
🚀 What’s Next?
Now you can build sections with shared layouts and sub-pages. So far you’ve only changed pages by typing URLs. Next you’ll add real clickable navigation with the Link component, so users can move between pages.