Render Nested Route Content with React Router v6 Outlet
Use <Outlet/> in React Router v6 to render child route UI inside a parent layout without duplicating shared UI.
16 May 2026, 05:05 UTC

When a child route matches but nothing renders
In React Router v6, a parent route can delegate part of its UI to child routes. The delegation point is <Outlet />, a placeholder element that the router fills with the matching child route's component. If the parent component omits <Outlet />, the router still matches the URL, but the child UI never appears.
This pattern is useful for pages that share a shell—such as a dashboard with a sidebar and header—while swapping only the main content area. The parent layout stays mounted, so state and event listeners in the shell survive navigation between child routes.
Worked configuration
Assumes React Router v6 (for example, react-router-dom@6) and a browser router already wrapped around the application.
import { Routes, Route, Outlet, Link } from 'react-router-dom';
function DashboardLayout() {
return (
Overview{' '}
Stats
{/* Child route UI renders here */}
);
}
function OverviewPage() {
return Overview metrics go here.;
}
function StatsPage() {
return Statistics go here.;
}
function App() {
return (
}>
} />
} />
);
}
The child route path="stats" is relative to its parent /dashboard, so the full URL is /dashboard/stats. The index route renders when the URL is exactly /dashboard. In both cases, DashboardLayout remains mounted and <Outlet /> swaps in OverviewPage or StatsPage.
Limits and common mistakes
- Missing outlet. If
DashboardLayoutreturns markup without<Outlet />, navigating to/dashboard/statsmatches the route but renders an empty<main>. The failure is silent; the router does not throw. - Outlet inside a link. Do not place
<Outlet />inside a<Link>or<a>element. The router can interpret the link target incorrectly and produce unexpected navigation. - Absolute child paths. A child route whose path starts with
/is treated as root-relative, not relative to the parent. Usepath="stats"for/dashboard/stats, notpath="/dashboard/stats"inside the nested route. - Deep nesting. React Router does not publish a hard nesting limit, but each level adds components to the React tree. Deeply nested layouts can slow re-renders and complicate debugging. Keep the hierarchy shallow.
- Lazy loading without Suspense. If a child route element uses
React.lazy, wrap the route tree or the outlet boundary in<Suspense fallback={...}>so the user sees a placeholder while the bundle loads.
How to verify the result
- Open the browser on
/dashboard/statsand open Developer Tools > Elements. - Confirm that the markup from
StatsPageappears inside the<main>element that contains<Outlet />, not outside it or in a second copy of the layout. - Navigate to
/dashboard. The header and shell should remain, while the outlet content changes toOverviewPage. If the shell remounts or the outlet stays empty, check that<Outlet />is present in the parent route's returned element. - Watch the browser console while navigating. React Router does not emit a specific "missing outlet" warning, so an empty outlet area with a matched URL is the primary signal of a configuration mistake.
Diagnostic decision
If a nested URL matches but the expected component is absent, inspect the parent route element first. The question is not whether the child route exists, but whether the parent component rendered <Outlet /> at the location where the child UI should appear.
This approach keeps shared layout code in one component and avoids duplicating headers, sidebars, or authentication wrappers across every child route.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.