Open karvas opened 1 year ago
Would like this as well
I am having this error too and it has been driving me mad trying to figure out what was going on until today when I narrowed it down to this plugin... Thanks @karvas for posting 🤪 Temporary work around is that I can delete the breadcrumb
"component" from my code so I can run localhost and then re-add it when I push my code to production... 🤷🏻♂️
Please
still waiting
I would have contributed this code but I see the repo has some PR from since 2021 that have not been resolved. Too bad, this would have been have great help for my project.
Still broken. :(
In lieu of this issue being resolved, can anyone suggest an alternate approach to breadcrumbs in nextjs13 ?
I used this lib, but now, I use React bootstrap breadcrumb instead
Le jeu. 20 avr. 2023 à 01:17, Alex Anschuetz @.***> a écrit :
In lieu of this issue being resolved, can anyone suggest an alternate approach to breadcrumbs in nextjs13 ?
— Reply to this email directly, view it on GitHub https://github.com/NiklasMencke/nextjs-breadcrumbs/issues/47#issuecomment-1515499623, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABMVBRS2R7WZOJAWWBUYTQ3XCBXBPANCNFSM6AAAAAARV4IXT4 . You are receiving this because you commented.Message ID: @.***>
I have removed all the excess package garbage and outdated build dependency stuff etc.. and made the code work with my nextjs13 project (new router requires different commands) plus next/link wont work with legacy tags inside. I will create new npm package
Added version for nextjs13 (using app dir and new next/navigation router) - might need seperate version for using pages dir npm install @marketsystems/nextjs13-appdir-breadcrumbs
(is embedded with "use client" as obviously wont work with router as a server component!)
I deleted so much of original repo I didnt do it as a github fork from original project but comments and issues can be added here: https://github.com/marketsystems/nextjs13-appdir-breadcrumbs
@marketsystems Is it a drop in replacement?
Created a PR for this here https://github.com/NiklasMencke/nextjs-breadcrumbs/pull/48
Desperate measure: For now I just installed it from my own github repo yarn add https://github.com/chozzz/nextjs-breadcrumbs
which is not ideal.
Hey everyone, bumped in to this as well which was very confusing. The package doesn't seem to be maintained anymore, however:
I made a copy of the src/index.tsx
(This file) file and put it in my own repo in a component I call: BreadCrumbs.tsx
. So now I can control and adapt the code myself and still use the foundation and functionality of this package. If I need to support the former Link behavior, add legacyBehavior
to the <Link>
s in BreadCrumbs.tsx
, if not, remove the <a>
tags inside the <Link>
s in BreadCrumbs.tsx
and you're good to go with the current Next.js version.
If you need App router support, consider using Marketsystem's solution above.
import React, { useEffect, useState } from "react";
import Link from "next/link";
import { useRouter } from "next/router";
/**
* Takes an URL String and removes query params and hash params
*
* @param url - The URL string
* @returns The transformed URL string
*
*/
const getPathFromUrl = (url: string): string => {
return url.split(/[?#]/)[0];
};
/**
* Takes a breadcrumb title (from url path) and replaces
* special chars to more readable chars
*
* @param title - The breadcrumb title
* @returns The transformed title or the result of the custom transformLabel function
*
*/
const convertBreadcrumb = (
title: string,
toUpperCase: boolean | undefined,
replaceCharacterList: Array<CharacterMap> | undefined,
transformLabel?: ((title: string) => React.ReactNode) | undefined
): React.ReactNode => {
let transformedTitle = getPathFromUrl(title);
if (transformLabel) {
return transformLabel(transformedTitle);
}
if (replaceCharacterList) {
for (let i = 0; i < replaceCharacterList.length; i++) {
transformedTitle = transformedTitle.replaceAll(
replaceCharacterList[i].from,
replaceCharacterList[i].to
);
}
}
// decode for utf-8 characters and return ascii.
return toUpperCase
? decodeURI(transformedTitle).toUpperCase()
: decodeURI(transformedTitle);
};
export interface Breadcrumb {
/** Breadcrumb title. Example: 'blog-entries' */
breadcrumb: string;
/** The URL which the breadcrumb points to. Example: 'blog/blog-entries' */
href: string;
}
export interface CharacterMap {
/** The source character or character pattern that should be replaced (e.g. 'ae') */
from: string;
/** The replacement into which the character should be replaced. */
to: string;
}
export interface BreadcrumbsProps {
/** If true, the default styles are used.
* Make sure to import the CSS in _app.js
* Example: true Default: false */
useDefaultStyle?: boolean;
/** The title for the very first breadcrumb pointing to the root directory. Example: '/' Default: 'HOME' */
rootLabel?: string | null;
/** Boolean indicator whether the root label should be omitted. Example: true Default: false */
omitRootLabel?: boolean;
/** Boolean indicator if the labels should be displayed as uppercase. Example: true Default: false */
labelsToUppercase?: boolean | undefined;
/** Array containing a list of specific characters that should be replaced in the label. This can be useful to convert special characters such as vowels. Example: [{ from: 'ae', to: 'ä' }, { from: '-', to: ' '}] Default: [{ from: '-', to: ' ' }] */
replaceCharacterList?: Array<CharacterMap> | undefined;
/** A transformation function that allows to customize the label strings. Receives the label string and has to return a string or React Component */
transformLabel?: ((title: string) => React.ReactNode) | undefined;
/** Array containing all the indexes of the path that should be omitted and not be rendered as labels. If we have a path like '/home/category/1' then you might want to pass '[2]' here, which omits the breadcrumb label '1'. Indexes start with 0. Example: [2] Default: undefined */
omitIndexList?: Array<number> | undefined;
/** An inline style object for the outer container */
containerStyle?: any | null;
/** Classes to be used for the outer container. Won't be used if useDefaultStyle is true */
containerClassName?: string;
/** An inline style object for the breadcrumb list */
listStyle?: any | null;
/** Classes to be used for the breadcrumb list */
listClassName?: string;
/** An inline style object for the inactive breadcrumb list item */
inactiveItemStyle?: any | null;
/** Classes to be used for the inactive breadcrumb list item */
inactiveItemClassName?: string;
/** An inline style object for the active breadcrumb list item */
activeItemStyle?: any | null;
/** Classes to be used for the active breadcrumb list item */
activeItemClassName?: string;
}
const defaultProps: BreadcrumbsProps = {
useDefaultStyle: false,
rootLabel: "Home",
omitRootLabel: false,
labelsToUppercase: false,
replaceCharacterList: [{ from: "-", to: " " }],
transformLabel: undefined,
omitIndexList: undefined,
containerStyle: null,
containerClassName: "",
listStyle: null,
listClassName: "",
inactiveItemStyle: null,
inactiveItemClassName: "",
activeItemStyle: null,
activeItemClassName: "",
};
/**
* A functional React component for Next.js that renders a dynamic Breadcrumb navigation
* based on the current path within the Next.js router navigation.
*
* Only works in conjunction with Next.js, since it leverages the Next.js router.
*
* By setting useDefaultStyle to true, the default CSS will be used.
* The component is highly customizable by either custom classes or
* inline styles, which can be passed as props.
*
* @param props - object of type BreadcrumbsProps
* @returns The breadcrumb React component.
*/
const Breadcrumbs = ({
useDefaultStyle,
rootLabel,
omitRootLabel,
labelsToUppercase,
replaceCharacterList,
transformLabel,
omitIndexList,
containerStyle,
containerClassName,
listStyle,
listClassName,
inactiveItemStyle,
inactiveItemClassName,
activeItemStyle,
activeItemClassName,
}: BreadcrumbsProps) => {
const router = useRouter();
const [breadcrumbs, setBreadcrumbs] = useState<Array<Breadcrumb> | null>(
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
style={containerStyle}
className={containerClassName}
aria-label="breadcrumbs"
>
<ol
style={listStyle}
className={useDefaultStyle ? "_2jvtI" : listClassName}
>
{!omitRootLabel && (
<li style={inactiveItemStyle} className={inactiveItemClassName}>
<Link href="/">
{convertBreadcrumb(
rootLabel || "Home",
labelsToUppercase,
replaceCharacterList,
transformLabel
)}
</Link>
</li>
)}
{breadcrumbs.length >= 1 &&
breadcrumbs.map((breadcrumb, i) => {
if (
!breadcrumb ||
breadcrumb.breadcrumb.length === 0 ||
(omitIndexList && omitIndexList.find((value) => value === i))
) {
return;
}
return (
<li
key={breadcrumb.href}
className={
i === breadcrumbs.length - 1
? activeItemClassName
: inactiveItemClassName
}
style={
i === breadcrumbs.length - 1
? activeItemStyle
: inactiveItemStyle
}
>
<Link href={breadcrumb.href}>
{convertBreadcrumb(
breadcrumb.breadcrumb,
labelsToUppercase,
replaceCharacterList,
transformLabel
)}
</Link>
</li>
);
})}
</ol>
</nav>
);
};
Breadcrumbs.defaultProps = defaultProps;
export default Breadcrumbs;
Then you can then import your own abstraction of a breadcrumb component or use it as before:
import React from 'react';
import Breadcrumbs from 'YourBreadCrumbComponent';
const MyBreadCrumb = () => {
return (
<Breadcrumbs
useDefaultStyle={true}
/>
);
};
export default MyBreadCrumb;
Error: Invalid <Link> with <a> child. Please remove <a> or use <Link legacyBehavior>. Learn more: https://nextjs.org/docs/messages/invalid-new-link-with-extra-anchor