How to implement nested Routes in React Router V6

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, if you have a parent route /service, the child routes could be

  • /service/development

  • /service/consulting

  • /service/outsourcing

Development, consulting, and outsourcing are static segments in the URL, however, these can also be dynamic. The ":serviceId" is a dynamic segment in the following example.

/services/:serviceId

Dynamic segments in routes are useful when you want to create a generic route that can match any number of variations of that route, such as /services/:serviceId which can match any service ID. We will talk more about the use of dynamic routes in nested routes a little later.

How to define the nested routes

You need two components to define nested routes: <Routes> and <Route>.

  <Routes>
        <Route index  path="/" element={ <Home/> } />
        <Route path="service/*" element={ <Service/> }>
               <Route path="development" element={ <Development />} />
               <Route path="consult" element={ <Consult/> } />
        </Route>       
 </Routes>

In the above example, the service route has two child routes: These child routes will be matched /service/development and /service/consult, and the relevant Component will be rendered. You can enter these URLs and see if they are rendering.

If you are in localhost:3000, you can enter the URLs as follows:

http://localhost:3000/service/development

http://localhost:3000/service/consult

Now, one thing you might have noticed is that the path prop of the parent route is “service/*”

The star segment here is used for matching URLs to routes. These are called path patterns. Because of this path pattern, for example, you can have any number of segments in the child URL.

  • localhost:3000/service/development/teams

  • localhost:3000/service/development/teams/projects

  • localhost:3000/service/outsource/remote/team

Implementing Nested route

I am using Vite.js to set up my project. If you are new to setting up a project in Vite.js for React projects, check this post on Basic React Router 6 setting up.

You can also look up the official document on Vite.js on Setting up the Vite.js project.

After setting up, Install Rect Router: npm install react-router-dom

Now, in main.jsx ( assuming you use Vite.js), add the following code

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


ReactDOM.render(
  <BrowserRouter>
    <App />
  </BrowserRouter>,
  document.getElementById('root')
);

In the src folder, create a folder named “components” and add five components: Home, Service, About, Development, and Consulting. Now, you should have Home.jsx, Service.jsx, and About.jsx , Development.jsx, Consulting.jsx in the src/components folder.

Now, add the following code to App.jsx

import Home from './components/Home'
import About from './components/About'
import Service from './components/Service'
import Development from './components/Development'
import Consult from './components/Consulting'
import { Routes, Route , Link } from 'react-router-dom'


export default function App() {
  return (
    <div>
      <nav>
        <ul>
          <li>
            <Link to="/">Home</Link>
          </li>
          <li>
            <Link to="service">Services</Link>
          </li>
          <li>
            <Link to="about">About</Link>
          </li>          
        </ul>
      </nav>

      <Routes>
        <Route index  path="/" Component={ Home } />
        <Route path="service/*" Component={ Service }>
               <Route path="development" Component={ Development } />
               <Route path="consult" Component={ Consult } />              
        </Route>
        <Route path="about" Component={ About } />         
      </Routes>   
    </div>
  );
}

Now, in the Service.jsx, add the following code.

import React from 'react'
import {Routes, Route } from 'react-router-dom';
import Development from './Development';
import Consulting from './Consulting';

export default function Service() {
  return (
    <div>
        <h2>Our Services</h2>       
          <div>
       <ul>
           <li>Software developement</li>
           <li>Consulting</li>
    </ul>
</div>
    </div>
  )
}

At this point, your nested routing setup is complete.

Now enter the following URL in the browser

Opps……did you get any errors….? Probably not something you can see on the dev tools.

But, you should notice that when you enter /service/development and service/consult do not seem to match their components.

Actually, it does match and there is nothing wrong with the code in App.jsx.

The issue here is that relevant components are not rendering.

So, what should you do about this?

<Outlet> Component

This compound is a new component added with React Router 6, and it reduces a decent number of lines of code if you had used previous versions of React Router.

The main purpose of the <Outlet> is to render the child route element within the parent route element. It will render the element that matches the route. If there is no match, it will render nothing( blank page ) if you have not specified a child index route.

So. now that you know about this component you might wonder, where to place this new component?

All you need to do is to import this component into the parent route element, which is the Service component.

import React from 'react'
import { Outlet } from 'react-router-dom'

export default function Service() {
  return (
    <div>
        <h2>Our Services</h2>       
          <div>
              <ul>
                 <li>Software developement</li>
                 <li>Consulting</li>
            </ul>
           <Outlet />
         </div>
    </div>
  )
}

Now, when you enter the following URL appropriate competent should be rendered within the parent route element.

URLComponent rendered
127.0.0.1:5173/service/development<Development>
127.0.0.1:5173/service/consult<Consulting>

Adding <Link> Component

In the production setting, no user is willing to enter the URL directly in the browser. Therefore we need to add links that send requests to child routes.

While you can use the traditional anchor tag in HTML, this requires additional code to implement navigation. So, the best option is to use the LINK component. You can use Link Component below.

Service.jsx

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

export default function Service() {
  return (
    <div>      
        <h2>Our Services</h2>    
        <div>
          <ul>            
            <li><Link to="development">Custom software developement</Link></li>
            <li><Link to="consult">Consulting</Link></li>
          </ul>
          <Outlet/>
        </div>    
    </div>
  )
}

What is an Index Route?

When you click on the Services link on the Main Menu what do you see? All you can see is a service page with a menu. The primary content is blank. This is because the <OUTLET> component only renders the child route elements. So, what is the solution? Index route.

The purpose of an index route is mainly to provide a default page or content for the parent route. This can be useful if the parent route is meant to have a default page or content that is different from what is displayed on child routes.

However, if you don't need a default page or content for the parent route, or if you want the same content to be displayed on both the parent and child routes, you can simply put the content in the parent route and omit the index route.

An index route is a child route that matches the parent route exactly, without any additional path segments. For example, if the parent route is "/service", an index route might have the path "/service" and match the parent route exactly. But, you do not need to specify the path prop instead you include the “index” prop.

<Routes>
        <Route path="/" Component={ Home } />
        <Route path="service/*" Component={ Service }>
               <Route index Component={ IndexService } />
               <Route path="development" Component={ Development } />
               <Route path="consult" Component={ Consult } />              
        </Route>
        <Route path="about" Component={ About } />        
 </Routes>

Nested routes with dynamic segments

You can also include dynamic segments in child routes. Dynamic segments of a URL starting with the colon ( : ). For example, :teamId is a dynamic segment in the URL

/services/teams/:teamId

teamId is called a params/URL params. These params are recorded under the params property in the match object. You can access the params with the useParams() hook. Then you can use the values inside the child component.

First, create a new component in src/components/Team.jsx. Add the following code

import React from 'react'
import { useParams  } from 'react-router-dom'

export default function Team() {
    const { teamId } = useParams();//teamId is the params passing with the URL
  return (
    <div>
      <h2>Team</h2>
       Your project is assiged to a {  teamId } team
    </div>
  )
}

Now, add a new route to Routes in App.jsx

<Routes>
        <Route path="/" Component={ Home } />
        <Route path="service/*" Component={ Service }>
               <Route index Component={ ServicesDesc } />
               <Route path="development" Component={ Development } />
               <Route path="consult" Component={ Consult } />      
               <Route path="team/:teamId" Component={ Team }/> {/*dynamic route*/}      
        </Route>
        <Route path="about" Component={ About } />  
</Routes>

Make sure to import the Team component to App.jsx.

Now that you completed the basic setup, you can test it by entering the following URLs in the browser.

examples:

Modifying the code in the parent route element

Now, except for developers or techies, not many people would like to have fun entering URLs in the browser. so, we need to add these links to the parent route element so that when a user clicks on a link Team component will render with the values passed via params.

Service.jsx

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

export default function Service() {
  return (
    <div>      
        <h2>Our Services</h2>    
        <div>
          <ul>            
            <li><Link to="development">Custom software developement</Link></li>
            <li><Link to="consult">Consulting</Link></li>

            { [ 'remote', 'in-house','freelancing' ].map( index =>
              <li>
                <Link to={ `team/${index }`}>{
                  index.charAt(0).toUpperCase() + index.slice(1) }
              </Link>
              </li>  )}           
          </ul>
          <Outlet/>
        </div>    
    </div>
  )
}

Wrapping up

I hope this post will help you set up a basic nested route. React Router v6 offers nested routes that allow developers to create hierarchical routing structures in their applications using the new Routes component. 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.