6

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...

jipay
  • 83
  • 1
  • 1
  • 6
  • Even i'm looking for this answer, if you have found the answer for the above query, please post the answer. I will accept it. – code_Knight Nov 10 '20 at 09:41

7 Answers7

21

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;
Mark Nunes
  • 827
  • 10
  • 23
5

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.

enter image description here

Ben Winding
  • 10,208
  • 4
  • 80
  • 67
3
    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)
illia chill
  • 1,652
  • 7
  • 11
  • 1
    Nice solution. How to add the homepage route here? – Ilir Feb 22 '22 at 19:37
  • You need to add it "manually" because your homepage has "/" url. So, when you create component to show `pathArray` you just add in the beginning with homepage – illia chill Feb 23 '22 at 10:14
1

Installation

yarn add nextjs-antd-breadcrumbs

Usage

The component needs to be used within Next.js and won't work in plain React. It will always display a dynamic Breadcrumb navigation, based on the current path of the Next router.

import React from 'react';
import Breadcrumbs from 'nextjs-antd-breadcrumbs';

const Example = () => {
  return <Breadcrumbs rootLabel="Home" omitRootLabel={false}/>;
};
0

I thought of using nextjs breadcrumbs but i was not able to align its style with antd (Ant Desing). And wanted to use the default breadcrumb component that antd was providing, thus, return some own simple component which uses next js router and some chunk of js.

const router = useRouter();
let routes= router.route.split('/');
let str='';
let hlinks=[];
routes.forEach((i,index,arr)=>{
    if(i.charAt(0)=='[')
    {
        i=i.slice(1);
        i=i.slice(0, i.length - 1);
        console.log(i)
        arr[index]=router.query[i];
    }
    str=str+arr[index]+'/';
    hlinks.push(str);
});
console.log(hlinks);
console.log(routes);
Abinash
  • 466
  • 7
  • 15
0

You can utilize breadcrumb with Next JS as below:

import { Breadcrumb } from "antd";
import styles from "../styles/Home.module.scss";
import { useRouter } from "next/router";
import React from "react";
import Link from "next/link";
import { HomeOutlined } from "@ant-design/icons";

const BreadcrumbComp = () => {
  const router = useRouter();
  const value = router.asPath.toLowerCase().split("/");
  console.log(value);

  const path = value.map(
    (value) => value.charAt(0).toUpperCase() + value.substring(1).toLowerCase()
  );

  return (
    <div>
      <Breadcrumb className={styles.breadcrumb}>
        <Breadcrumb.Item>
          <Link href="/home">
            <HomeOutlined />
          </Link>
        </Breadcrumb.Item>
        <Breadcrumb.Item>{path[1] + " / " + path[2]}</Breadcrumb.Item>
      </Breadcrumb>
    </div>
  );
};

export default BreadcrumbComp;
  • Here, path[0] = " " , path[1] = " Array_value_one", path[2] = "Array value two". Though my folder structure was as like pages/main/routePages.jsx – Anup Dhakal May 16 '22 at 07:01
-1

You can implement Breadcrumbs on Next JS with Antd Design as below:

import { Breadcrumb } from "antd";
import styles from "../styles/Home.module.scss";
import { useRouter } from "next/router";
import React from "react";
import Link from "next/link";
import { HomeOutlined } from "@ant-design/icons";

const BreadcrumbComp = () => {
  const router = useRouter();
  const value = router.asPath.toLowerCase().split("/");
  console.log(value);

  const path = value.map(
    (value) => value.charAt(0).toUpperCase() + value.substring(1).toLowerCase()
  );

  return (
    <div>
      <Breadcrumb className={styles.breadcrumb}>
        <Breadcrumb.Item>
          <Link href="/home">
            <HomeOutlined />
          </Link>
        </Breadcrumb.Item>
        <Breadcrumb.Item>{path}</Breadcrumb.Item>
      </Breadcrumb>
    </div>
  );
};

export default BreadcrumbComp;