I'd like to make a breadcrumb for my NextJS application, and I'd like to know if there is a good or practical way to do it?
I'd like to go through Ant Design, but the example of the component with React Router doesn't want to work for me.
I need your help please...
If you are using the Next.js routing system I suggest you have a look at nextjs-breadcrumbs, it is simple and effective.
Or if you prefer to write your own component use their code as reference.
import React, { useEffect, useState } from 'react';
import { useRouter } from 'next/router';
import Link from 'next/link';
const convertBreadcrumb = string => {
return string
.replace(/-/g, ' ')
.replace(/oe/g, 'ö')
.replace(/ae/g, 'ä')
.replace(/ue/g, 'ü')
.toUpperCase();
};
const Breadcrumbs = () => {
const router = useRouter();
const [breadcrumbs, setBreadcrumbs] = useState(null);
useEffect(() => {
if (router) {
const linkPath = router.asPath.split('/');
linkPath.shift();
const pathArray = linkPath.map((path, i) => {
return { breadcrumb: path, href: '/' + linkPath.slice(0, i + 1).join('/') };
});
setBreadcrumbs(pathArray);
}
}, [router]);
if (!breadcrumbs) {
return null;
}
return (
<nav aria-label="breadcrumbs">
<ol className="breadcrumb">
<li>
<a href="/">HOME</a>
</li>
{breadcrumbs.map((breadcrumb, i) => {
return (
<li key={breadcrumb.href}>
<Link href={breadcrumb.href}>
<a>
{convertBreadcrumb(breadcrumb.breadcrumb)}
</a>
</Link>
</li>
);
})}
</ol>
</nav>
);
};
export default Breadcrumbs;
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;
}
In this case, either the route is shown, or the label is shown if it exists in the Route2LabelMap
variable, like "Your Barrels" does.
const router = useRouter()
const linkPath = router.asPath.split('/');
linkPath.shift();
const pathArray = linkPath.map((path, i) => {
return { breadcrumb: path, href: '/' + linkPath.slice(0, i + 1).join('/') };
});
console.log(pathArray)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With