MUI ^7 breadcrumbs for any React app. Works with Vite, CRA, Remix, and plain React. Next.js is optional (the package was originally built for it). Pass your own
LinkComponentwhen you want client-side routing. Optional URL helpers and SEO JSON-LD. Zero runtime dependencies (peers only).
| Item | Value | Badge |
|---|---|---|
| Version | 0.2.1 (do not use 0.2.0) | |
| GitHub repo | github.com/ameshkin/nextcrumbs | |
| CI | .github/workflows/ci.yml |
|
| npm package | @ameshkin/nextcrumbs | |
| Install | npm i @ameshkin/nextcrumbs |
|
| Peer deps | @mui/material@^7, @mui/icons-material@^7, @emotion/*@^11, react@>=18, react-dom@>=18(Optional: react-router-dom@>=6) |
|
| Types | TypeScript | |
| License | MIT | |
| Bundle size | bundlephobia | |
| Deps status | libraries.io |
0.2.0 is broken. Its
exportspointed at./public/*while the tarball only shipsdist/. Use 0.2.1+. Details:docs/changes.md.
- Features
- Requirements
- Install
- Quick Start (Vite / any React)
- Quick Start (Next.js)
- Auto from URL (Next App Router)
- React Router
- Subpath exports
- Props
- Icon & Separator Examples
- Accessibility & SEO
- Docs
- Dependency Checks
- Troubleshooting
- FAQ
- Contributing
- License
- Works without Next.js. Vite, CRA, Remix, and plain React are first-class. Next.js is optional.
- MUI ^7 breadcrumbs under the hood (accessible, stable)
- Pluggable
LinkComponent. Use MUI's default link, React RouterLink(linkProp="to"), ornext/link - Optional URL → items helpers:
usePathBreadcrumbs(client) and RSC-safebuildPathBreadcrumbs - React Router helper on a subpath only (
useReactRouterBreadcrumbs) - JSON-LD helpers for schema.org
BreadcrumbList(noexample.comdefault) - First-class
maxItems/ collapse,size,truncate, and optionaljsonLdOrigin - Tree-shakable subpath exports (
/breadcrumbs,/hooks/*,/utils/*) - Fully typed with TypeScript
- Trusted Publishing workflow (
.github/workflows/publish.yml) for OTP-free CI releases
Originally built for Next.js App Router. The public API is router-agnostic, so the bundler does not matter.
- Node 20.19+ (or 22.12+) for developing / CI
- React 18+ (React 19 supported in tests)
@mui/material^7 (MUI 8/9 are outside this peer range)@mui/icons-material^7 (default home / separator icons)@emotion/reactand@emotion/styled^11- Next.js is not required. Use it only if your app already does (App Router examples assume 13.4+)
- (Optional)
react-router-dom6+ only if you import the React Router subpath (common with Vite)
npm i @ameshkin/nextcrumbs
# required peers
npm i @mui/material @mui/icons-material @emotion/react @emotion/styled react react-dom
# optional: only if you use the React Router subpath hook (typical Vite SPA)
npm i react-router-domYou do not need Next.js. Vite and other React toolchains only need the peers above (plus React Router if you use that subpath).
No Next.js. Default MUI links work out of the box:
import { Breadcrumbs } from "@ameshkin/nextcrumbs";
export function HeaderTrail() {
return (
<Breadcrumbs
items={[
{ label: "Home", href: "/" },
{ label: "Products", href: "/products" },
{ label: "New" }
]}
/>
);
}import { Link as RouterLink } from "react-router-dom";
import { Breadcrumbs } from "@ameshkin/nextcrumbs";
import { useReactRouterBreadcrumbs } from "@ameshkin/nextcrumbs/hooks/useReactRouterBreadcrumbs";
export function Trail() {
const items = useReactRouterBreadcrumbs({ rootLabel: "Home" });
return (
<Breadcrumbs
LinkComponent={RouterLink}
linkProp="to"
items={items}
/>
);
}You can also pass useLocation().pathname into usePathBreadcrumbs if you prefer the path helper.
Wrap the app in Vite as usual (BrowserRouter, MUI ThemeProvider). No Next.js plugins or "use client" directives are required for this path.
See also docs/vanilla-json.md and docs/react-router.md.
Optional. Use this only in a Next.js App Router project:
"use client";
import Link from "next/link";
import { NextCrumb } from "@ameshkin/nextcrumbs";
// Also available as: import { Breadcrumbs } from "@ameshkin/nextcrumbs";
export default function HeaderTrail() {
return (
<NextCrumb
LinkComponent={Link}
items={[
{ label: "Dashboard", href: "/" },
{ label: "Products", href: "/products" },
{ label: "New" }
]}
/>
);
}See full guide: docs/next-router.md
"use client";
import Link from "next/link";
import { usePathname } from "next/navigation";
import { Breadcrumbs, usePathBreadcrumbs } from "@ameshkin/nextcrumbs";
export default function AutoTrail() {
const pathname = usePathname();
const items = usePathBreadcrumbs(pathname, {
baseHref: "/",
rootLabel: "Home",
labelMap: { new: "Create" },
exclude: ["_private"]
});
return <Breadcrumbs LinkComponent={Link} items={items} />;
}See full guide: docs/react-router.md
import { MemoryRouter, Routes, Route, Link as RouterLink } from "react-router-dom";
import { Breadcrumbs } from "@ameshkin/nextcrumbs";
import { useReactRouterBreadcrumbs } from "@ameshkin/nextcrumbs/hooks/useReactRouterBreadcrumbs";
function Trail() {
const items = useReactRouterBreadcrumbs({
rootLabel: "Home",
exclude: [/^_/]
});
return <Breadcrumbs LinkComponent={RouterLink} linkProp="to" items={items} />;
}
export default function Demo() {
return (
<MemoryRouter initialEntries={["/catalog/hats"]}>
<Routes>
<Route path="/" element={<Trail />} />
<Route path="/catalog/hats" element={<Trail />} />
</Routes>
</MemoryRouter>
);
}react-router-dom is an optional peer. Import the hook only from @ameshkin/nextcrumbs/hooks/useReactRouterBreadcrumbs (alias: useRRBreadcrumbs). Use linkProp="to" so React Router receives to while a native href remains for right-click open. The main package entry does not import React Router.
| Import path | Contents |
|---|---|
@ameshkin/nextcrumbs |
Breadcrumbs, NextCrumb, usePathBreadcrumbs, buildPathBreadcrumbs, getLinkRoutingProps, JSON-LD helpers + types |
@ameshkin/nextcrumbs/breadcrumbs |
Component only |
@ameshkin/nextcrumbs/hooks/usePathBreadcrumbs |
Path helper (client hook) |
@ameshkin/nextcrumbs/hooks/useReactRouterBreadcrumbs |
React Router helper (useReactRouterBreadcrumbs, useRRBreadcrumbs) |
@ameshkin/nextcrumbs/utils/buildPathBreadcrumbs |
RSC-safe pure path → crumbs helper |
@ameshkin/nextcrumbs/utils/jsonld |
toJsonLd, BreadcrumbJsonLd, breadcrumbsToJsonLd (no "use client") |
@ameshkin/nextcrumbs/package.json |
Package metadata |
Published files live under dist/ (main / types / exports all point there).
| Prop | Type | Default | Description |
|---|---|---|---|
items |
{ label: string; href?: string; icon?: React.ReactNode; title?: string; external?: boolean }[] |
required | The breadcrumb trail; last item usually has no href. |
LinkComponent |
React.ElementType |
@mui/material/Link |
Custom link component (for example Next.js Link). |
linkProp |
"href" | "to" |
"href" |
"to" for React Router. Always still sets native href so right-click / open in new tab works. |
maxItems / itemsBeforeCollapse / itemsAfterCollapse / expandText |
number / string | - | First-class MUI collapse controls for deep trails. |
size |
"small" | "medium" | "large" |
"medium" |
Crumb text size. |
truncate |
boolean | number |
false |
Ellipsis long labels (true = 160px, or pass max width px). |
jsonLdOrigin |
string |
- | When set, also emits BreadcrumbList JSON-LD for these items (relative URLs resolve against it). |
muiProps |
Omit<MUIBreadcrumbsProps,"children" | collapse props> |
- | Extra props for MUI <Breadcrumbs />. |
separatorIcon |
React.ReactNode |
ChevronRightIcon |
Icon/node placed between items. |
homeLabel |
string |
"Home" |
Display label for the home crumb (homeHref). |
homeHref |
string |
"/" |
Href that receives the automatic Home icon (not label match). |
ariaLabel |
string |
"Breadcrumb" |
aria-label on the nav. |
dense |
boolean |
false |
Tighter gap between items. |
sx |
SxProps<Theme> |
- | Root styles (default margin is 0). |
itemSx / linkSx / currentSx / contentSx / iconSx / labelSx |
SxProps<Theme> |
- | Style slots for crumbs. |
Same options. Prefer buildPathBreadcrumbs in Server Components (@ameshkin/nextcrumbs/utils/buildPathBreadcrumbs).
| Option | Type | Default | Description |
|---|---|---|---|
baseHref |
string |
"/" |
Root href for the first crumb. |
labelMap |
Record<string,string> |
{} |
Override labels by URL segment. |
exclude |
string[] |
[] |
Skip specific segments. |
decode |
boolean |
true |
decodeURIComponent each segment. |
rootLabel |
string |
"Dashboard" |
Label for the root/home breadcrumb. |
transformLabel |
(segment: string) => string |
- | Custom label formatter. |
Import from @ameshkin/nextcrumbs/hooks/useReactRouterBreadcrumbs.
| Option | Type | Default | Description |
|---|---|---|---|
rootLabel |
string |
- | Optional first crumb label linking to /. |
basePath |
string |
- | Strip a leading base path when building crumbs. |
decode |
boolean |
true |
Decode each segment before labeling. |
exclude |
(string | RegExp)[] |
[] |
Skip segments by string or regex. |
mapSegmentLabel |
(segment, index, segments) => string | null |
- | Customize a label or return null to hide a segment. |
import Link from "next/link";
import NavigateNextIcon from "@mui/icons-material/NavigateNext";
import HomeOutlinedIcon from "@mui/icons-material/HomeOutlined";
import { Breadcrumbs } from "@ameshkin/nextcrumbs";
<Breadcrumbs
LinkComponent={Link}
separatorIcon={<NavigateNextIcon fontSize="small" />}
items={[
{ label: "Home", href: "/", icon: <HomeOutlinedIcon /> },
{ label: "Products", href: "/products" },
{ label: "Gadgets" }
]}
/>;- Uses MUI's accessible
<Breadcrumbs aria-label={ariaLabel}>(default"Breadcrumb"). - Current page gets
aria-current="page". - Minimal DOM footprint; last item is usually text without
href.
Pass your real origin. Relative hrefs are left unresolved if origin is omitted (no example.com default).
import { Breadcrumbs } from "@ameshkin/nextcrumbs";
<Breadcrumbs items={items} jsonLdOrigin="https://yoursite.com" LinkComponent={Link} />Or use the helpers:
import { Breadcrumbs, BreadcrumbJsonLd, breadcrumbsToJsonLd, toJsonLd } from "@ameshkin/nextcrumbs";
<BreadcrumbJsonLd crumbs={breadcrumbsToJsonLd(items)} origin="https://yoursite.com" />
<Breadcrumbs items={items} />
const jsonLd = toJsonLd(
[{ name: "Home", href: "/" }, { name: "Products" }],
{ origin: "https://yoursite.com" }
);See docs/vanilla-json.md.
| Guide | Path |
|---|---|
| Vite / any React + JSON-LD | docs/vanilla-json.md |
| React Router | docs/react-router.md |
| Next.js App Router (optional) | docs/next-router.md |
| Subpath exports (CI / GitLab) | docs/gitlab.md |
| Export & API changelog | docs/changes.md |
| Docs index | docs/README.md |
npm ls @mui/material @mui/icons-material @emotion/react @emotion/styled react react-dom
# only if using the React Router subpath
npm ls react-router-domYou are importing the React Router hook. Either install the peer or stop importing that subpath:
npm install react-router-dom// React Router apps
import { useReactRouterBreadcrumbs } from "@ameshkin/nextcrumbs/hooks/useReactRouterBreadcrumbs";
// Next.js (no React Router)
import { Breadcrumbs, usePathBreadcrumbs } from "@ameshkin/nextcrumbs";You are on 0.2.0. Upgrade:
npm i @ameshkin/nextcrumbs@^0.2.1This package peers @mui/material@^7. Do not run npm audit fix --force to pull MUI 9. Keep your app on MUI 7 while using NextCrumbs 0.2.x.
Note. NextCrumbs does not require Next.js. It is a React + MUI component that runs in Vite, CRA, Remix, and other React apps. The name comes from the original Next.js target. Next.js is optional. Use the answers below by topic.
Do I need Next.js?
No. Install the package and MUI peers, then render <Breadcrumbs />. No Next.js plugins or "use client" directives are required outside the App Router.
Does it work with Vite?
Yes. There is no Vite-specific plugin. See Quick Start (Vite / any React) and docs/vanilla-json.md.
Does it work with React Router?
Yes. Import the hook from the React Router subpath and pass LinkComponent={RouterLink} with linkProp="to":
import { useReactRouterBreadcrumbs } from "@ameshkin/nextcrumbs/hooks/useReactRouterBreadcrumbs";
// <Breadcrumbs LinkComponent={RouterLink} linkProp="to" items={items} />linkProp="to" sets React Router's to and still keeps a native href (right-click open / middle-click). Install react-router-dom only when you use that subpath.
Do I need react-router-dom for Next.js?
No. Use the main entry and usePathBreadcrumbs. Only install React Router if you import @ameshkin/nextcrumbs/hooks/useReactRouterBreadcrumbs. If a bundler errors on that subpath, see Troubleshooting.
How do I style the current (last) crumb?
Omit href on the last item so it renders as text. Style it with currentSx or your theme.
Can I disable icons?
Yes. Do not pass icon on items. The automatic Home icon only appears when href === homeHref (default "/"). Change homeHref or pass your own icon if you want different behavior.
Can I emit JSON-LD from <Breadcrumbs>?
Yes. Pass jsonLdOrigin (your real site origin):
<Breadcrumbs items={items} jsonLdOrigin="https://yoursite.com" />Which version should I install?
Use 0.2.1+. Do not use 0.2.0 (broken exports pointing at missing ./public/*).
npm i @ameshkin/nextcrumbs@^0.2.1Why is MUI capped at ^7?
A wider peer like >=7 lets npm pull MUI 8 or 9, which breaks apps still on MUI 7. Keep NextCrumbs on ^7 for 0.2.x.
| Topic | Doc |
|---|---|
| Vite / no Next.js / JSON-LD | docs/vanilla-json.md |
| React Router | docs/react-router.md |
| Next.js App Router (optional) | docs/next-router.md |
| Subpath exports | docs/gitlab.md |
| Changelog | docs/changes.md |
npm ci
npm run cinpm run ci runs typecheck, unit tests, and build (same pipeline as .github/workflows/ci.yml).
Keep MUI peers on ^7. Do not widen them to >=7.