← Back to React Course | Chapter 8: Routing | Lesson 9 of 10

Handling 404 Pages

A 404 page is like a friendly note left on a locked door saying 'this room doesn't exist' instead of leaving visitors staring at a blank hallway.

Adding a Catch-All Route

A Route defined with path='*' matches literally any URL that no earlier route already matched. Placing this as the last Route inside your Routes block gives unmatched URLs somewhere to land instead of showing a blank page.

Note: Test your 404 page by visiting a made-up URL like /this-does-not-exist during development.

Warning: A wildcard route placed before your real routes will match everything first, preventing any of your actual pages from ever rendering.

Example: Adding a Catch-All Route

markup
// Run in your local React project (npm install required)
import { Routes, Route } from 'react-router-dom';

function Home() { return <p>Home</p>; }
function NotFound() { return <h1>404 - Page Not Found</h1>; }

function AppRoutes() {
  return (
    <Routes>
      <Route path="/" element={<Home />} />
      <Route path="*" element={<NotFound />} />
    </Routes>
  );
}

⚠️ This example uses an npm package with no CDN build available here — run this in your local React project.

Making the 404 Page Helpful

A good 404 page does more than say 'not found' — it reassures the user and gives them an obvious way to recover, usually a link back to the homepage or a search box. This turns a dead end into a small, graceful redirect.

Note: Include a Link (not a plain <a>) back to home, so recovering from a 404 stays a smooth client-side navigation.

Warning: A bare 404 with no explanation or way out is a poor experience — always give the user their next step.

Example: Making the 404 Page Helpful

markup
// Run in your local React project (npm install required)
import { Link } from 'react-router-dom';

function NotFound() {
  return (
    <div>
      <h1>404 - Page Not Found</h1>
      <p>Sorry, that page doesn't exist.</p>
      <Link to="/">Go back home</Link>
    </div>
  );
}

⚠️ This example uses an npm package with no CDN build available here — run this in your local React project.

Nested 404s for a Specific Section

The same wildcard pattern works inside nested routes too, letting a specific section of your app (like /dashboard/*) show its own contextual 'not found' message rather than the app-wide one, while other sections still use the global 404.

Note: A section-specific 404 can keep the section's shared layout (like a sidebar) visible, which the global 404 usually wouldn't.

Warning: Having both a global and several nested wildcard routes can get confusing — document clearly which one handles which cases.

Example: Nested 404s for a Specific Section

markup
// Run in your local React project (npm install required)
import { Routes, Route, Outlet } from 'react-router-dom';

function DashboardLayout() { return <div><nav>Dashboard Nav</nav><Outlet /></div>; }
function DashboardNotFound() { return <p>No such dashboard page</p>; }

function AppRoutes() {
  return (
    <Routes>
      <Route path="/dashboard" element={<DashboardLayout />}>
        <Route path="*" element={<DashboardNotFound />} />
      </Route>
    </Routes>
  );
}

⚠️ This example uses an npm package with no CDN build available here — run this in your local React project.

Common Mistakes
  1. Forgetting to add a wildcard route at all, leaving unmatched URLs rendering completely blank.
  2. Placing the wildcard route somewhere other than last, letting it accidentally swallow other routes.
  3. Not giving the 404 page a way back to safety, like a link to the home page.
Chapter Summary
  • A Route with path='*' matches any URL not matched by an earlier, more specific route.
  • It must be the last Route inside Routes so it doesn't shadow real pages.
  • A good 404 page explains what happened and offers a link back to a known-good page.
  • This pattern also works for nested routes, catching unmatched paths within a specific section.
Browser Support

Requires npm install react-router-dom — not available via CDN in this sandbox.

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.