Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Nested routes and layouts

The blog's pages share the header, menu and footer; only the middle changes. Instead of repeating them on every page, you make a layout — a component with the shared parts and a slot for the current page. Page routes are nested inside the layout route, and the slot is marked with the Outlet component.

The layout component

Create src/components/Layout.jsx:

// src/components/Layout.jsx
import { Outlet } from 'react-router';
import Nav from './Nav.jsx';
 
export default function Layout() {
  return (
    <>
      <header>
        <Nav />
      </header>
      <main>
        <Outlet />
      </main>
      <footer>Blog, 2026</footer>
    </>
  );
}

Outlet is where React Router puts the component of the nested route that matches the address.

Nested routes

In src/App.jsx the page routes move inside the layout route:

// src/App.jsx
import { Route, Routes } from 'react-router';
import Layout from './components/Layout.jsx';
import HomePage from './pages/HomePage.jsx';
import AboutPage from './pages/AboutPage.jsx';
import PostPage from './pages/PostPage.jsx';
 
export default function App() {
  return (
    <Routes>
      <Route element={<Layout />}>
        <Route index element={<HomePage />} />
        <Route path="about" element={<AboutPage />} />
        <Route path="posts/:id" element={<PostPage />} />
        <Route path="*" element={<p>Page not found</p>} />
      </Route>
    </Routes>
  );
}

Open /, /about and /posts/3 — all three pages have the menu and footer, with their own page inside main. Nav can now be removed from App: it lives in the layout.

The index route

index instead of path means "show when the address equals the parent's address". The layout has no path, so its parent is the root /, and HomePage is shown on the home page.

FormAddress
Route indexThe parent's address, here /
Route path="about"/about
Route path="posts/:id"/posts/3

Nested route paths are written without a leading / — they continue the parent's path.

Nesting inside a page

Pages themselves can have nested routes. Let a post have a comments tab at /posts/3/comments:

// src/App.jsx
<Route path="posts/:id" element={<PostPage />}>
  <Route path="comments" element={<PostComments />} />
</Route>
// src/pages/PostPage.jsx
import { Link, Outlet } from 'react-router';
 
// at the end of the post markup:
<Link to="comments">Show comments</Link>
<Outlet />

Following the link changes the address to /posts/3/comments, and the PostComments component appears under the post. The comments path in Link is relative — it is appended to the current address. PostComments reads id with the same useParams and loads /posts/3/comments from the API.

Common mistake

If you forget Outlet in the layout, nested pages never appear — every address shows only the header and footer:

// Wrong: there is nowhere to render the page.
export default function Layout() {
  return (
    <>
      <Nav />
      <footer>Blog, 2026</footer>
    </>
  );
}

Every route that has child routes must render an Outlet in its component.

Thanks for reading!

Donate to the site — we work hard for you.