# Changelog
All notable changes to `breadcrumb-core` are documented here.
This project follows [Semantic Versioning](https://semver.org/).
---
## [3.0.0] — 2026-04-27
### ✨ New features
#### Progressive per-item loading
In v1/v2 the entire breadcrumb blocked on the slowest async label. In v3, static labels render instantly and each async label resolves independently — you see `Home / Products / ▓▓▓▓ / Reviews` immediately, then the skeleton swaps to `iPhone 15 Pro` when it arrives:
```tsx
// Already on by default — nothing to change
// Custom per-item skeleton
(
)}
/>
```
#### Custom route matchers — RegExp & function
The `path` field now accepts three forms:
```ts
// String (unchanged)
{ path: '/products/:id', label: 'Product' }
// RegExp with named groups (v3)
{ path: /^\/p\/(?\d+)$/, label: ({ params }) => `Product ${params.id}` }
// Fully custom function (v3)
{
path: (pathname) => {
const m = pathname.match(/^\/items-(\w+)$/)
return m ? { slug: m[1] } : null
},
label: ({ params }) => `Item: ${params.slug}`,
}
```
#### i18n locale-prefix stripping
Automatically strip and re-apply locale prefixes without defining separate routes per locale:
```tsx
// Works for /en/products/42 and /fr/products/42 with the same routes
// Read the detected locale anywhere
const locale = useBreadcrumbLocale() // → 'fr'
```
#### `transformLabel` prop
Post-process every resolved label globally — useful for title-casing, translations, or appending meta:
```tsx
label.toUpperCase()}
/>
// Or with i18n:
t(label)}
/>
```
#### `CollapsibleBreadcrumb` component
Improves on v2's static `maxItems` — collapsed items expand inline when clicked:
```tsx
import { CollapsibleBreadcrumb } from 'breadcrumb-core/ui'
// Home / ••• / Reviews ← click ••• to expand
```
#### `useActiveRoute()` hook
Shorthand for `useBreadcrumb().at(-1)` — the currently active route item:
```ts
const active = useActiveRoute()
// → { path: '/products/42/reviews', label: 'Reviews', ... } | null
```
#### `useBreadcrumbLocale()` hook
Read the detected i18n locale inside any component:
```ts
const locale = useBreadcrumbLocale() // → 'en' | 'fr' | null
```
#### `buildBreadcrumbsProgressive` utility
New core function for framework-agnostic progressive resolution:
```ts
import { buildBreadcrumbsProgressive } from 'breadcrumb-core'
await buildBreadcrumbsProgressive(pathname, routes, (items) => {
// called immediately with skeletons, then again per resolved async label
render(items)
})
```
#### `invalidateLabelCache` accepts `RouteConfig` directly
```ts
// v2 (string path):
invalidateLabelCache('/products/:id', { id: '42' })
// v3 (RouteConfig or string path both work):
invalidateLabelCache(routes.find(r => r.path === '/products/:id')!, { id: '42' })
```
#### JSON-LD only includes resolved items
In v3, the `injectJsonLd` script only lists items that have finished resolving — no empty-label entries during progressive loading.
### 🔧 Improvements
- `progressiveLoading` defaults to `true` — existing code benefits automatically
- `renderItemSkeleton` is preferred over `renderSkeleton` for progressive UX; `renderSkeleton` still works as a full-replacement fallback
- `syncDocumentTitle` updates incrementally as labels resolve
- All adapters pass through `locales` and `transformLabel` automatically via `...rest`
### 💥 Breaking changes
None. v3 is fully backward compatible with v2. All new features are additive or opt-in.
---
## [2.0.0] — 2026-04-26
### Added
- Wildcard routes (`/docs/*`) and optional params (`:id?`)
- `cacheTtl` per route + `invalidateLabelCache()` utility
- `onMatch` per route for analytics
- `onNavigate` on ``
- `useBreadcrumbHistory()` hook
- `ariaLabel` and `onItemClick` props on ``
- `pill` theme in `/ui`
- `route` field on `BreadcrumbItem`
- `maxHistory` on ``
---
## [1.0.0] — 2026-04-26
### Initial release
- `BreadcrumbProvider` + `AutoBreadcrumb` component
- Async label resolution with cache
- Schema.org JSON-LD injection, `document.title` sync
- `maxItems` collapsing, hidden route segments
- Adapters: `react-router`, `next`, `tanstack-router`, `headless`, `ui`
- `useBreadcrumb()` and `useBreadcrumbLoading()` hooks
- `StyledBreadcrumb` with light / dark / minimal themes + `BreadcrumbSkeleton`