Automatically generating a breadcrumb with React Router

Matty Williams
4 min readNov 3, 2019

--

Photo by Karsten Würth (@karsten.wuerth) on Unsplash

Providing the user a path of going back in a UI is a must, so adding a navigational element that shows the route they’ve been on is a no brainier.

Enter breadcrumbs…

I’ve been building React applications for 3 years now, and always seem to forget about the breadcrumbs until it’s too late. I searched everywhere for a quick and simple solution, and found very little. So here’s a way to automatically generate a breadcrumb from your already existing routes.

Just interested in the source code? You can find it here: https://github.com/mw999/react-breadcrumbs

Defining our routes

The first thing we need need to do is define an array of our routes before rendering them. I often do this when building apps, allowing me to create my own API for rendering routes, as well as having a simple list of all of my app routes.

Our app will consist of three pages, a list of pizzas, a page to edit a specific pizza, and a page to view the selected pizzas toppings.

export default [
{ path: "/pizza", name: "Pizzas", Component: Pizza },
{ path: "/pizza/:pizzaId", name: "Edit Pizza", Component: EditPizza },
{
path: "/pizza/:pizzaId/toppings",
name: "Pizza Toppings",
Component: Toppings
}
];

Defining a structure for our routes doesn’t tie us to one routing library, and also lends itself nicely to snapshot testing.

import routes from "./routes";test("correct routes are exported", () => {
expect(routes.map(({ name, path }) => (
`${name}: ${path}`
)).toMatchSnapshot();
});

With this array we are going to loop over each of them, rendering a React Router Route component.

const App = () => (
<Router>
<Switch>
{routes.map(({ path, Component }, key) => (
<Route exact path={path} key={key} render={Component} />
))}
</Switch>
</Router>
)

Generating a breadcrumb

Our app now has a working router. We can access the index page of our pizza, get a specific pizza, then view a specific pizzas toppings. Let’s build our breadcrumb…

{routes.map(({ path, name, Component }, key) => (
<Route
exact
path={path}
key={key}
render={props => {
const crumbs = routes
// Get all routes that contain the current one.
.filter(({ path }) => props.match.path.includes(path))
// Swap out any dynamic routes with their param values.
// E.g. "/pizza/:pizzaId" will become "/pizza/1"
.map(({ path, ...rest }) => ({
path: Object.keys(props.match.params).length
? Object.keys(props.match.params).reduce(
(path, param) => path.replace(
`:${param}`, props.match.params[param]
), path
)
: path,
...rest
}));
console.log(`Generated crumbs for ${props.match.path}`);
crumbs.map(({ name, path }) => console.log({ name, path }));
return (
<div className="p-8">
<Component {...props} />
</div>
);
}}
/>
))}

Every time we hit a route, we generate an array of breadcrumbs that have a name and a path. This is done by using our defined list of routes, finding any route that shares the same path as the current one, dynamically swapping out any route parameters (the pizza ID).

With this array we can now build a nice React Component!

Showing the crumbs

Using the array of crumbs, we want to render links that take the user to the previous pages. The name will be used as the title, and the path as the link. We only want to show the breadcrumbs if we have more than one crumb. For example we don’t want to show anything if they land on the initial Pizza page.

We also don’t want the last item to be a link, as that is the current route we are on.

import React from "react";
import { Link } from "react-router-dom";
const Breadcrumbs = ({ crumbs }) => {
// Don't render a single breadcrumb.
if (crumbs.length <= 1) {
return null;
}
return (
<div>
{/* Link back to any previous steps of the breadcrumb. */}
{crumbs.map(({ name, path }, key) =>
key + 1 === crumbs.length ? (
<span key={key}>
{name}
</span>
) : (
<Link key={key} to={path}>
{name}
</Link>
)
)}
</div>
);
};
export default Breadcrumbs;

And there we go, automatically generate a path back for the user when on a nested route. We don’t have to think about breadcrumbs when building new pages, they will appear with their given name and links.

Useful resources

--

--