Define your routes once. Get auto-generated breadcrumbs everywhere — with async labels, SEO JSON-LD injection, and adapters for every major React router.
Route changes silently break them. Dynamic labels get duplicated. Nobody wins.
// Written by hand on every page 😩 <Breadcrumb> <Item>Home</Item> <Item>Products</Item> <Item> {'{ /* fetch name yourself */}'} {product.name} </Item> <Item>Reviews</Item> </Breadcrumb> // Repeat on 40 other pages... // Route changes = silent breakage 💀
// Define once ✅ export const routes = [ { path: "/", label: "Home" }, { path: "/products", label: "Products" }, { path: "/products/:id", label: async ({ params }) => getProductName(params.id) }, { path: "/products/:id/reviews", label: "Reviews" }, ] // Any page — zero code needed <AutoBreadcrumb /> // → Home / Products / iPhone 15 / Reviews
The library reads your route definitions once and handles everything automatically.
/products/123/reviews becomes four typed ancestor segments
Each segment matched against your config with named param extraction
Strings used directly. Async functions awaited and cached for instant back-nav
Your <AutoBreadcrumb> renders. Skeleton shown while async resolves
The combination no existing solution provides.
Labels can be async functions. Results are cached by path + params so back-navigation is instant. Pass renderSkeleton for a loading state.
One prop enables automatic BreadcrumbList structured data injection for Google rich results. No extra libraries.
Mark layout-only routes with hidden: true and they're skipped in the breadcrumb without affecting your routing at all.
Set syncDocumentTitle and the browser tab updates to iPhone 15 — Products — MyApp automatically on every navigation.
Use useBreadcrumb() to get raw items and build fully custom renders with your own design system. Zero opinions on markup.
Set maxItems={4} and deep paths collapse in the middle with … automatically. No extra logic needed.
Each adapter reads pathname automatically. Same API, every framework.
2M+ combined weekly npm installs — none covering all the cases.
| Tool | Async labels | SEO JSON-LD | Multi-router | Headless hook | Cache |
|---|---|---|---|---|---|
| breadcrumb-core ✦ | ✓ | ✓ | ✓ | ✓ | ✓ |
| use-react-router-breadcrumbs | ✗ | ✗ | ✗ | ✓ | ✗ |
| antd Breadcrumb | ✗ | ✗ | ✗ | ✗ | ✗ |
| Manual per-page | ✗ | ✗ | ✓ | ✗ | ✗ |
Full TypeScript support. Every prop documented.
| Prop | Default | Description |
|---|---|---|
| separator | "/" | Between items |
| maxItems | — | Collapse middle with … |
| showHome | true | Include root item |
| injectJsonLd | false | Schema.org JSON-LD |
| syncDocumentTitle | false | Auto document.title |
| appName | — | Appended to synced title |
| renderItem | — | Custom item renderer fn |
| renderSkeleton | — | Loading placeholder |
interface RouteConfig { path: string label: | string | (({ params }) => string | Promise<string>) icon?: ReactNode hidden?: boolean } // useBreadcrumb() returns: interface BreadcrumbItem { path: string label: string params: RouteParams isLast: boolean icon?: ReactNode }
One install. One provider. Zero breadcrumb code per page. Ever.