Introduction
Many applications share persistent UI, such as a sidebar, header, or tab bar, across multiple pages while only the inner content changes. Instead of repeating that shared layout in every route's component, React Router v6 supports nested routes: a parent Route renders a layout component, and its child Routes render inside that layout wherever the layout places an Outlet. This keeps layout code in one place and makes route hierarchies mirror your UI hierarchy.
Cricket analogy: A persistent scoreboard shell staying up while the batting details change underneath is like React Router's Outlet, the stadium's main display frame (layout) stays constant while only the current-over details (child route) update inside it.
Syntax
import { Routes, Route, Outlet, Link } from 'react-router-dom';
function App() {
return (
<Routes>
<Route path="/dashboard" element={<DashboardLayout />}>
<Route index element={<DashboardHome />} />
<Route path="settings" element={<Settings />} />
<Route path="billing" element={<Billing />} />
</Route>
</Routes>
);
}
function DashboardLayout() {
return (
<div>
<aside>
<Link to="/dashboard">Home</Link>
<Link to="/dashboard/settings">Settings</Link>
<Link to="/dashboard/billing">Billing</Link>
</aside>
<main>
<Outlet />
</main>
</div>
);
}Explanation
When a Route has children, its element becomes a layout: React Router renders it whenever the URL matches the parent path, and the child Route whose path also matches renders wherever that layout places the Outlet component. Child route paths are relative to their parent, so 'settings' under '/dashboard' matches '/dashboard/settings'. An index Route (marked with the 'index' prop instead of a path) renders by default when the URL matches the parent path exactly, such as '/dashboard' itself. This pattern can be nested arbitrarily deep, letting you compose layouts within layouts, for example a top-level app shell containing a dashboard layout that itself contains a settings layout with its own sub-tabs.
Cricket analogy: An index Route rendering by default at the parent path, like '/dashboard', is like a stadium's main scoreboard defaulting to the live match view unless a specific replay ('/dashboard/settings') is explicitly requested.
Example
function Settings() {
return (
<div>
<h3>Settings</h3>
<Routes>
<Route path="profile" element={<ProfileSettings />} />
<Route path="security" element={<SecuritySettings />} />
</Routes>
</div>
);
}
// Alternative: declare deeper nesting directly in the route tree
<Route path="/dashboard" element={<DashboardLayout />}>
<Route path="settings" element={<SettingsLayout />}>
<Route path="profile" element={<ProfileSettings />} />
<Route path="security" element={<SecuritySettings />} />
</Route>
</Route>Output
Visiting '/dashboard' renders DashboardLayout with DashboardHome inside its Outlet (matching the index route). Navigating to '/dashboard/settings' keeps the same sidebar and shell from DashboardLayout rendered, but swaps only the Outlet's content to the Settings component, avoiding any flicker or re-render of the sidebar. Going one level deeper to '/dashboard/settings/profile' would render SettingsLayout's own Outlet with ProfileSettings, while both DashboardLayout and SettingsLayout stay mounted around it.
Cricket analogy: Navigating between overs while the main scoreboard frame stays mounted, only the ball-by-ball detail panel swaps, is like DashboardLayout's sidebar persisting while its Outlet content changes between Home and Settings without any flicker.
Key Takeaways
- A parent Route with children acts as a shared layout for those child routes.
- The Outlet component marks where a layout renders its matched child route.
- Child route paths are relative to the parent, e.g. 'settings' under '/dashboard' becomes '/dashboard/settings'.
- An index Route renders by default when the URL matches the parent path exactly.
- Nesting can go arbitrarily deep, composing layouts within layouts without duplicating shared UI.
Practice what you learned
1. What component marks the location inside a layout where a matched child route renders?
2. In a nested route tree, how are child route paths resolved?
3. What is the purpose of an index Route?
4. What is the main benefit of nesting routes under a layout component?
Was this page helpful?
You May Also Like
React Router Basics
Learn how to add client-side routing to a React app using React Router v6's Routes, Route, Link, and NavLink components.
Dynamic Routing in React
Use URL parameters and the useParams and useNavigate hooks to build dynamic, data-driven routes in React Router.
Component Composition in React
Learn how to build complex UIs by combining small, reusable components using composition patterns.
Related Reading
Related Study Notes in Web Development
Browse all study notesWebSockets Study Notes
Web Development · 30 topics
Web DevelopmentWebAssembly Study Notes
WebAssembly · 30 topics
Web DevelopmentgRPC Study Notes
Protocol Buffers · 30 topics
Web DevelopmentSpring Boot Study Notes
Java · 30 topics
Web DevelopmentFlask Study Notes
Python · 30 topics
Web DevelopmentDjango Study Notes
Python · 30 topics