|
1 | | -# Next Crumb |
| 1 | +_# Next Crumb |
2 | 2 |
|
3 | 3 | > MUI 7 Breadcrumbs with **Next.js Link** support, optional **URL-based generation**, and **SEO microdata**. Router-agnostic, zero runtime deps. |
4 | 4 |
|
5 | | -| Item | Value | |
6 | | -|-----------------------|-------| |
7 | | -| **GitHub repo** | [github.com/ameshkin/nextcrumbs](https://github.com/ameshkin/nextcrumbs) | |
8 | | -| **npm package name** | `@ameshkin/nextcrumbs` | |
9 | | -| **Install** | `npm i @ameshkin/nextcrumbs` | |
10 | | -| **Peer deps** | `@mui/material@^7`, `@mui/icons-material@^7`, `react@>=18`, `react-dom@>=18` | |
11 | | -| **CI badge** | [](https://github.com/ameshkin/nextcrumbs/actions) | |
12 | | -| **npm badge** | [](https://www.npmjs.com/package/@ameshkin/nextcrumbs) | |
13 | | -| **Types badge** |  | |
14 | | -| **License badge** | [](LICENSE) | |
15 | | -| **Bundle size badge** | [](https://bundlephobia.com/package/@ameshkin/nextcrumbs) | |
16 | | -| **Deps badge** | [](https://libraries.io/npm/%40ameshkin%2Fnextcrumbs) | |
| 5 | +| Item | Value | Badge | |
| 6 | +|-----------------|-------------------------------------------------------------------------------------------|-------| |
| 7 | +| **GitHub repo** | [github.com/ameshkin/nextcrumbs](https://github.com/ameshkin/nextcrumbs) | — | |
| 8 | +| **CI (main)** | `.github/workflows/ci-main.yml` | [)](https://github.com/ameshkin/nextcrumbs/actions/workflows/ci-main.yml) | |
| 9 | +| **CI (dev)** | `.github/workflows/ci-dev.yml` | [)](https://github.com/ameshkin/nextcrumbs/actions/workflows/ci-dev.yml) | |
| 10 | +| **npm package** | [@ameshkin/nextcrumbs](https://www.npmjs.com/package/@ameshkin/nextcrumbs) | [](https://www.npmjs.com/package/@ameshkin/nextcrumbs) | |
| 11 | +| **Install** | `npm i @ameshkin/nextcrumbs` | [](https://github.com/ameshkin/nextcrumbs/actions/workflows/install.yml) | |
| 12 | +| **Peer deps** | `@mui/material@^7`, `@mui/icons-material@^7`, `react@>=18`, `react-dom@>=18` |  | |
| 13 | +| **Types** | TypeScript |  | |
| 14 | +| **License** | MIT | [](LICENSE) | |
| 15 | +| **Bundle size** | bundlephobia | [](https://bundlephobia.com/package/@ameshkin/nextcrumbs) | |
| 16 | +| **Deps status** | libraries.io | [](https://libraries.io/npm/%40ameshkin%2Fnextcrumbs) | |
17 | 17 |
|
18 | 18 | --- |
19 | 19 |
|
|
26 | 26 | - [Auto from URL (Next App Router)](#auto-from-url-next-app-router) |
27 | 27 | - [Props](#props) |
28 | 28 | - [Icon & Separator Examples](#icon--separator-examples) |
| 29 | +- [Automated Testing](#automated-testing) |
29 | 30 | - [Accessibility & SEO](#accessibility--seo) |
30 | 31 | - [Dependency Checks](#dependency-checks) |
31 | | -- [FAQ](#faq) |
32 | 32 | - [Contributing](#contributing) |
33 | 33 | - [License](#license) |
34 | 34 |
|
|
48 | 48 |
|
49 | 49 | - React **18+** |
50 | 50 | - @mui/material **7+** |
51 | | -- (Optional) @mui/icons-material **7+** for built-in icons |
| 51 | +- (Optional) @mui/icons-material **7+** |
52 | 52 | - Next.js **13.4+** (if using Next + App Router) |
53 | 53 |
|
54 | 54 | --- |
|
59 | 59 | npm i @ameshkin/nextcrumbs |
60 | 60 | # peer deps |
61 | 61 | npm i @mui/material @mui/icons-material react react-dom |
62 | | -```` |
63 | | - |
64 | | -> Using pnpm or yarn? Replace `npm i` with your package manager’s command. |
65 | | - |
66 | | ---- |
67 | | - |
68 | | -## Quick Start (Next.js) |
69 | | - |
70 | | -Manual items with `next/link`: |
71 | | - |
72 | | -```tsx |
73 | | -"use client"; |
74 | | -import Link from "next/link"; |
75 | | -import { Breadcrumbs } from "@ameshkin/nextcrumbs"; |
76 | | -
|
77 | | -export default function HeaderTrail() { |
78 | | - return ( |
79 | | - <Breadcrumbs |
80 | | - LinkComponent={Link} |
81 | | - items={[ |
82 | | - { label: "Dashboard", href: "/" }, |
83 | | - { label: "Products", href: "/products" }, |
84 | | - { label: "New" } |
85 | | - ]} |
86 | | - /> |
87 | | - ); |
88 | | -} |
89 | | -``` |
90 | | -
|
91 | | ---- |
92 | | -
|
93 | | -## Auto from URL (Next App Router) |
94 | | -
|
95 | | -Generate items from the current pathname: |
96 | | -
|
97 | | -```tsx |
98 | | -"use client"; |
99 | | -import Link from "next/link"; |
100 | | -import { usePathname } from "next/navigation"; |
101 | | -import { Breadcrumbs, usePathBreadcrumbs } from "@ameshkin/nextcrumbs"; |
102 | | -
|
103 | | -export default function AutoTrail() { |
104 | | - const pathname = usePathname(); |
105 | | - const items = usePathBreadcrumbs(pathname, { |
106 | | - baseHref: "/", |
107 | | - labelMap: { new: "Create" }, |
108 | | - exclude: ["_private"] |
109 | | - }); |
110 | | -
|
111 | | - return <Breadcrumbs LinkComponent={Link} items={items} />; |
112 | | -} |
113 | | -``` |
114 | | -
|
115 | | ---- |
116 | | -
|
117 | | -## Props |
118 | | -
|
119 | | -### `<Breadcrumbs />` |
120 | | -
|
121 | | -| Prop | Type | Default | Description | |
122 | | -| --------------- | ------------------------------------------------------ | -------------------- | ---------------------------------------------------------------- | |
123 | | -| `items` | `{ label: string; href?: string; icon?: ReactNode }[]` | **required** | The breadcrumb trail; last item usually has no `href`. | |
124 | | -| `LinkComponent` | `ElementType` | `@mui/material/Link` | Custom link component (e.g., Next.js `Link`). | |
125 | | -| `muiProps` | `Omit<MUIBreadcrumbsProps, "children">` | — | Pass-through props to MUI `<Breadcrumbs />`. | |
126 | | -| `separatorIcon` | `ReactNode` | `ChevronRightIcon` | Icon/node placed between items. | |
127 | | -| `homeLabel` | `string` | `"Dashboard"` | If an item’s label matches this, it gets a Home icon by default. | |
128 | | -| `withSchema` | `boolean` | `true` | Adds `schema.org/BreadcrumbList` microdata. | |
129 | | -
|
130 | | -### `usePathBreadcrumbs(pathname, options?)` |
131 | | -
|
132 | | -| Option | Type | Default | Description | |
133 | | -| ---------- | ----------------------- | ------- | ---------------------------------- | |
134 | | -| `baseHref` | `string` | `"/"` | Root href for the first crumb. | |
135 | | -| `labelMap` | `Record<string,string>` | `{}` | Override labels by segment. | |
136 | | -| `exclude` | `string[]` | `[]` | Skip specific path segments. | |
137 | | -| `decode` | `boolean` | `true` | `decodeURIComponent` each segment. | |
138 | | -
|
139 | | ---- |
140 | | -
|
141 | | -## Icon & Separator Examples |
142 | | -
|
143 | | -Change the separator and home icon behavior: |
144 | | -
|
145 | | -```tsx |
146 | | -import Link from "next/link"; |
147 | | -import ChevronRightIcon from "@mui/icons-material/ChevronRight"; |
148 | | -import NavigateNextIcon from "@mui/icons-material/NavigateNext"; |
149 | | -import HomeOutlinedIcon from "@mui/icons-material/HomeOutlined"; |
150 | | -import { Breadcrumbs } from "@ameshkin/nextcrumbs"; |
151 | | -
|
152 | | -<Breadcrumbs |
153 | | - LinkComponent={Link} |
154 | | - separatorIcon={<NavigateNextIcon fontSize="small" />} |
155 | | - items={[ |
156 | | - { label: "Dashboard", href: "/", icon: <HomeOutlinedIcon /> }, |
157 | | - { label: "Products", href: "/products" }, |
158 | | - { label: "Gadgets" } |
159 | | - ]} |
160 | | -/>; |
161 | | -``` |
162 | | -
|
163 | | -* Any MUI icon works for `separatorIcon` or per-item `icon`. |
164 | | -* If you set `homeLabel="Home"`, the component shows a Home icon automatically when a crumb’s label is `"Home"`. |
165 | | -
|
166 | | ---- |
167 | | -
|
168 | | -## Accessibility & SEO |
169 | | -
|
170 | | -* Uses MUI’s accessible `<Breadcrumbs aria-label="breadcrumbs">`. |
171 | | -* Adds **schema.org** `BreadcrumbList` microdata by default (set `withSchema={false}` to disable). |
172 | | -* Minimal DOM/no extra wrappers (uses `display: contents` for the list wrapper). |
173 | | -
|
174 | | ---- |
175 | | -
|
176 | | -## Dependency Checks |
177 | | -
|
178 | | -Make sure peer deps resolve cleanly: |
179 | | -
|
180 | | -```bash |
181 | | -# in your app |
182 | | -npm ls @mui/material @mui/icons-material react react-dom |
183 | 62 | ``` |
184 | 63 |
|
185 | | -Optional size/security checks: |
186 | | -
|
187 | | -* Size: [https://bundlephobia.com/package/@ameshkin/nextcrumbs](https://bundlephobia.com/package/@ameshkin/nextcrumbs) |
188 | | -* Vulnerabilities (example): `npx snyk test` or GitHub Advanced Security (CodeQL) |
189 | | -
|
190 | | ---- |
191 | | -
|
192 | | -## FAQ |
193 | | -
|
194 | | -**Does it work with React Router?** |
195 | | -Yes—pass your router’s `<Link>` as `LinkComponent`. The UI is MUI; navigation is your router. |
196 | | -
|
197 | | -**How do I change the last crumb’s style?** |
198 | | -The last item usually has no `href`. You can add conditional styles by checking `href` presence in your `items` or wrap this component with your own style logic. |
199 | | -
|
200 | | -**Can I disable icons entirely?** |
201 | | -Yes—don’t pass `icon` and set `homeLabel` to a non-matching value. |
202 | | -
|
203 | | ---- |
204 | | -
|
205 | | -## Accessibility & SEO |
206 | | -
|
207 | | -This component previously supported `schema.org` microdata via a `withSchema` and `withJsonLd` prop. These have been **removed** for the following reasons: |
208 | | -
|
209 | | -- ⚠️ **Google no longer consistently indexes client-side microdata** (e.g. via React or `dangerouslySetInnerHTML`) unless it's rendered server-side. |
210 | | -- 🧼 Breadcrumb JSON-LD tags added via `<script>` often **conflict with route-based apps** (e.g. dynamic segments in Next.js). |
211 | | -- 🔍 Most modern SEO guidance encourages **server-side or static rendering** of JSON-LD, not runtime injection. |
212 | | -- 🔧 Removing these props results in **simpler DOM output**, cleaner markup, and improved developer control. |
213 | | -
|
214 | | -**If you need structured breadcrumbs for SEO**, we recommend injecting them at the page level with your own layout component, using `<script type="application/ld+json">` manually for static pages only. |
215 | | -
|
216 | | -This component still provides: |
217 | | -
|
218 | | -- Accessible markup (`aria-label`, correct role semantics) |
219 | | -- Customizable separator, label, and icon logic |
220 | | -- Dynamic routing support via the `items` prop or `usePathBreadcrumbs` helper |
221 | | -
|
222 | | -
|
223 | | -## Contributing |
224 | | -
|
225 | | -* CI badge above expects a workflow at `.github/workflows/ci.yml`. |
226 | | -* Please run `npm run build` before sending a PR. |
227 | | -* Keep peer ranges broad enough for MUI 7 / React 18–19. |
228 | | -
|
229 | | ---- |
230 | | -
|
231 | | -## License |
232 | | -
|
233 | | -[MIT](LICENSE) |
234 | | -
|
235 | | -``` |
236 | | -
|
237 | | -
|
238 | | ---- |
239 | | -
|
240 | | -## Additional Example — Minimal AutoTrail |
241 | | -
|
242 | | -> Simple usage with default behavior (no `labelMap`, `exclude`, or `baseHref`) |
243 | | -
|
244 | | -```tsx |
245 | | -"use client"; |
246 | | -import { usePathname } from "next/navigation"; |
247 | | -import { Breadcrumbs, usePathBreadcrumbs } from "@ameshkin/nextcrumbs"; |
248 | | -import Link from "next/link"; |
249 | | -
|
250 | | -export default function AutoTrail() { |
251 | | - const pathname = usePathname(); |
252 | | - const items = usePathBreadcrumbs(pathname); |
253 | | -
|
254 | | - return <Breadcrumbs LinkComponent={Link} items={items} />; |
255 | | -} |
256 | | -``` |
257 | 64 |
|
258 | | -✅ Great for dashboards or quick scaffolded layouts. Automatically capitalizes, cleans up slugs, and converts URL segments into breadcrumb labels. |
0 commit comments