This my approach to bread crumbs in nextjs, it uses the router.asPath
to get the link to the crumb and the router.route
to get the label if it exists in the Route2LabelMap
.
pages/example.jsx
export default function Page() {
return <>
<BreadCrumbs />
<h1>My Page</h1>
</>
}
components/BreadCrumbs.jsx
import Link from "next/link";
import { useRouter } from "next/router";
import React from "react";
/*
interface BreadCrumb {
route: string;
label: string;
link: string;
}
*/
const Route2LabelMap = {
"/": "Home",
"/profile/[username]/barrels": "Your Barrels",
"/barrels": "Barrel List",
"/barrels/[barrel_id]": "Barrel",
"/barrels/[barrel_id]/settings": "Settings",
};
export function BreadCrumbs() {
const router = useRouter();
const [crumbs, setCrumbs] = React.useState([]);
React.useEffect(() => {
const segmentsPath = router.asPath.split("/");
const segmentsRoute = router.route.split("/");
const crumbLinks = CombineAccumulatively(segmentsPath);
const crumbLabels = CombineAccumulatively(segmentsRoute);
const crumbs = crumbLinks.map((link, index) => {
const route = crumbLabels[index];
const crumb = {
link: link,
route: route,
label: Route2LabelMap[route] || route,
};
return crumb;
});
setCrumbs(crumbs);
console.log({
router,
segmentsPath,
segmentsRoute,
crumbLinks,
crumbLabels,
crumbs,
});
}, [router.route]);
return (
<div className="w-full flex gap-1">
{crumbs.map((c, i) => {
return (
<div className="flex items-center gap-1" key={i}>
{(i > 0) ? <div>{'>'}</div> : null}
<div className={(i == (crumbs.length - 1) ? 'bg-blue-300 ' : 'bg-gray-300 ') + " px-2 py-1 rounded-xl"}>
<Link href={c.link}>
<a>{c.label}</a>
</Link>
</div>
</div>
);
})}
</div>
);
}
function CombineAccumulatively(segments) {
/*
when segments = ['1','2','3']
returns ['1','1/2','1/2/3']
*/
const links = segments.reduce((acc, cur, curIndex) => {
const last = curIndex > 1 ? acc[curIndex - 1] : "";
const newPath = last + "/" + cur;
acc.push(newPath);
return acc;
}, []);
return links;
}
Rendered BreadCrumbs
In this case, either the route is shown, or the label is shown if it exists in the Route2LabelMap
variable, like "Your Barrels" does.
