Hello Sunil
nested-routes-with-react-router-feature-image

The Guide to Nested Routes with React Router

We use nested routing in our React application so that a parent component has control over its child component at the route level.

In this tutorial we will learn how to use Nested Routes with React Router.

In order to get you started, create a new React project. Afterward, install React Router and read the following tutorial to get yourself aligned to what follows next.

What Are Nested Routes?

Nested routes in React Router are a way of defining routes in a hierarchical manner. In this arrangement, a route( parent route ) can have child routes. Each child route represents a portion of the URL.

For example, on a user page one gets presented multiple tabs (e.g. Profile, Account) to navigate through a user’s information.

By clicking these tabs, the URL in the browser will change, but instead of replacing the whole page, only the content of the tab gets replaced.

nested-routes-react-router-example

In the following we will recreate this scenario with React Router.

Setting Up The Project

To be able to follow along, add these lines of code to the file:

App.css

nav a {
	text-decoration: none;
	font-weight: bold;
	color: #000;
	padding-left: 10px;
}

Home.jsx

import React from 'react';

const Home = () => {
  return <div>This is Home Page.</div>;
};

export default Home;

User.jsx

import React from 'react'

const User = () => {
	return (
		<div>This is User Page.</div>
	)
}

export default User

Profile.jsx

import React from 'react'

const Profile = () => {
	return (
		<div>You are now in Profile page.</div>
	)
}

export default Profile

Account.jsx

import React from 'react';

const Account = () => {
  return <div>You are now in Account page.</div>;
};

export default Account;

PageNotFound.jsx

import React from 'react'

const PageNotFound = () => {
	return (
		<div>PageNotFound</div>
	)
}

export default PageNotFound

App.jsx

import './App.css';

function App() {
  return (
    <>
      <h1>React Router</h1>
    </>
  );
}

export default App;

main.jsx

In the main.jsx file, enter the following:

import React from 'react';
import ReactDOM from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom';
import App from './App.jsx';
import './index.css';

ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </React.StrictMode>
);

This should hold everything in our app where routing is needed. That means, if we need routing in our entire app, we must wrap our higher component with BrowserRouter.

Defining Routes

To illustrate how this works and how you can implement nested routes step by step in React yourself, we will start off with the following example:

import './App.css';
import { Routes, Route, Link } from 'react-router-dom';
import Home from './Home';
import User from './User';
import PageNotFound from './PageNotFound';


function App() {
  return (
    <>
      <h1>React Router</h1>

      <nav>
        <Link to="/home">Home</Link>
        <Link to="/user">User</Link>
      </nav>
      

      <Routes>
        <Route index element={<Home />} />
        <Route path="home" element={<Home />} />
        <Route path="user" element={<User />} />
        <Route path="*" element={<PageNotFound />} />
      </Routes>
    </>
  );
}

export default App;

In this function component we have matching Link and Route components from React Router for the /home and /user routes.

Furthermore, we have a so-called Index Route loaded with the Home component and a so-called No Match Route loaded with the PageNotFound component.

Also Read: A Complete Beginner’s Guide to React Router

Both act as fallback routes. From here, we will explore the concept of Nested Route.

Nested Routes in React Router

We will continue working on the User component, because this is the place where we want to have the nested routing via tabs.

Therefore, we will create a new set of Link components (which will be our un-styled tabs) which navigate a user to their profile and their account.

User.jsx

import { Link } from 'react-router-dom';

const User = () => {
  return (
    <>
      <h1>User</h1>
      <p>This is User Page.</p>
      <nav>
        <Link to="/user/profile">Profile</Link>
        <Link to="/user/account">Account</Link>
      </nav>
    </>
  );
};

export default User;

We are using absolute paths here to navigate a user from their profile to their account and vice versa, however, we could also use relative paths as a best practice.

Because the User component sits in the /user route, the Link components can anticipate their parent route (here: /user) and just append relative paths (here: profile and account) to it (e.g. /user/profile):

User.jsx

import { Link } from 'react-router-dom';

const User = () => {
  return (
    <>
      <h1>User</h1>
      <p>This is User Page.</p>
      <nav>
        <Link to="profile">Profile</Link>
        <Link to="account">Account</Link>
      </nav>
    </>
  );
};

export default User;

At this time, when we attempt to click one of these links in our React application, we would get stranded at our No Match Route i.e PageNotFound.

This tells us that we didn’t map these routes (here: /user/profile and /user/account) to any actual Route components yet.

Therefore, we will add these two new routes as so-called Nested Routes to our /user route:

App.jsx

import './App.css';
import { Routes, Route, Link } from 'react-router-dom';
import Home from './Home';
import User from './User';
import PageNotFound from './PageNotFound';
import Profile from './Profile';
import Account from './Account';


function App() {
  return (
    <>
      <h1>React Router</h1>

      <nav>
        <Link to="/home">Home</Link>
        <Link to="/user">User</Link>
      </nav>
      

      <Routes>
        <Route index element={<Home />} />
        <Route path="home" element={<Home />} />
        <Route path="user" element={<User />}>
          <Route path="profile" element={<Profile />} />
          <Route path="account" element={<Account />} />
        </Route>
        <Route path="*" element={<PageNotFound />} />
      </Routes>
    </>
  );
}

export default App;

The Route components map to the Link components in a one to one relationship now. However, there can be more than one Link component linking to the same route, so it’s actually a one to many relationship.

When testing this in the browser, we will see that only the User components shows up and not its nested Profile component nor its nested Account component when clicking their respective links.

react-router-nested-component-without-outlet-component

We are missing the crucial Outlet component from React Router:

User.jsx

import { Link, Outlet } from 'react-router-dom';

const User = () => {
  return (
    <>
      <h1>User</h1>
      <p>This is User Page.</p>
      <nav>
        <Link to="profile">Profile</Link>
        <Link to="account">Account</Link>
      </nav>
      <Outlet />
    </>
  );
};

export default User;

The Outlet component renders the matching child route with its respective component (here either Profile or Account component) from the parent Routes’ component collection of Route components.

Nested-routes-react-router-example-outlet

If there is no /profile and no /account route matching (e.g. /user/settings), you will see only the User component showing up.

To avoid this, you can add a combination of Index and No Match Routes. Afterward, the default route will be the /profile route:

App.jsx

import './App.css';
import { Routes, Route, Link } from 'react-router-dom';
import Home from './Home';
import User from './User';
import PageNotFound from './PageNotFound';
import Profile from './Profile';
import Account from './Account';

function App() {
  return (
    <>
      <h1>React Router</h1>

      <nav>
        <Link to="/home">Home</Link>
        <Link to="/user">User</Link>
      </nav>


      <Routes>
        <Route index element={<Home />} />
        <Route path="home" element={<Home />} />
        <Route path="user" element={<User />}>
          <Route index element={<Profile />} />
          <Route path="profile" element={<Profile />} />
          <Route path="account" element={<Account />} />
          <Route path="*" element={<PageNotFound />} />
        </Route>
        <Route path="*" element={<PageNotFound />} />
      </Routes>

    </>
  );
}

export default App;

That’s it. While the User component always renders the tabs as navigation, its content (Outlet) gets replaced by the matching nested route (either Profile or Account component based on /user/profile or /user/account route).

react-router-nested-component-with-outlet-component

If none of these routes are matched when visiting the /user route, the application will show either the Profile component (if route matches exactly /user) or the PageNotFound component (if route does not match, e.g. /user/setting) showing up.

Conclusion

We hope this post has helped you set up a basic nested route. This feature improves code organization and maintainability while enhancing user experience.

Nested routes are a valuable addition to React Router and should be considered when building complex applications.

How useful was this post?

Click on a star to rate it!

Average rating 0 / 5. Vote count: 0

No votes so far! Be the first to rate this post.

We are sorry that this post was not useful for you!

Let us improve this post!

Tell us how we can improve this post?

Similar articles you may like

Sunil Pradhan

Hi there 👋 I am a front-end developer passionate about cutting-edge, semantic, pixel-perfect design. Writing helps me to understand things better.

Add comment

Stay Updated

Want to be notified when our article is published? Enter your email address below to be the first to know.

Sunil Pradhan

Hi there 👋 I am a front-end developer passionate about cutting-edge, semantic, pixel-perfect design. Writing helps me to understand things better.