useBreadcrumbs
Builds a page's breadcrumb trail from its loader data, with a Home-plus-title fallback and a remembered referrer on product pages.
import { useBreadcrumbs } from '@salla.sa/twilight-theme-engine/hooks';In plain words
Breadcrumbs are the "Home › Chairs › Wooden chair" trail at the top of a page. Pass the page object your route's loader returned (a loader is the function that fetches a page's data before it renders), and you get an array of { name, url } to render as links.
When the loader sent no trail, you still get one: Home, then the page title.
Signature
function useBreadcrumbs(page?: Page | null): Breadcrumb[]
interface Breadcrumb { name: string; url: string }
// Page: { title; slug; id?; url?; parent?; breadcrumbs?: Breadcrumb[] }Try it live
- Home
- Help
- Shipping policy
[{"name":"Home","url":"/"},{"name":"Help","url":"/help"},{"name":"Shipping policy","url":"/help/shipping"}]import { useBreadcrumbs } from '@salla.sa/twilight-theme-engine/hooks';
import type { Page } from '@salla.sa/twilight-theme-engine/types';
// `page` is what your route loader returned, e.g.
// { title: 'Shipping policy', slug: 'page-single', breadcrumbs: [...] }
export function Crumbs({ page }: { page: Page }) {
const items = useBreadcrumbs(page);
return (
<ol>
{items.map((crumb) => (
<li key={crumb.url}>{crumb.name}</li>
))}
</ol>
);
}
Example
import { Link } from '@salla.sa/twilight-theme-engine/components/common';
import { useBreadcrumbs } from '@salla.sa/twilight-theme-engine/hooks';
import type { Page } from '@salla.sa/twilight-theme-engine/types';
export function Crumbs({ page }: { page: Page }) {
const items = useBreadcrumbs(page);
if (items.length === 0) return null;
return (
<nav aria-label="Breadcrumb">
<ol className="breadcrumbs">
{items.map((crumb, index) => (
<li key={`${crumb.url}-${index}`}>
{index < items.length - 1 ? <Link to={crumb.url}>{crumb.name}</Link> : <span>{crumb.name}</span>}
</li>
))}
</ol>
</nav>
);
}
How it behaves
With no
page, it returns[]. With a non-emptypage.breadcrumbs, it returns them as they are.Without
page.breadcrumbs:[]on the home route, otherwise[{ name: t('common.titles.home'), url: '/' }, { name: page.title, url: location.pathname }].On a page whose slug is
product.single, the middle crumbs are replaced after mount by the last page the shopper visited, read fromsessionStorageunderbreadcrumb-referrer:[first, referrer, last]. Every other page with apageobject writes itself there.Location and home detection come from the engine context (
useLocation(),useIsHome()), never fromwindow.location.The engine's
<Breadcrumb page={page} />component is built on it.It has no subpath of its own: import it from
@salla.sa/twilight-theme-engine/hooks.
Gotchas
Its effect depends on the
pageobject itself. Loader data is stable, but apagebuilt inline during render is new every time, so the effect runs (and writessessionStorage) on every render. Memoise hand-built page objects withuseMemo.On product pages the trail changes after mount (loader crumbs on the server, referrer crumbs in the browser), a visible swap on a slow device.
The fallback Home crumb's
urlis the literal'/', with no locale or store segment. Render crumbs with the engineLink(as the engine'sBreadcrumbTraildoes), not a plain<a>, which would leave the current language.