Breadcrumbs
Contribute one localized crumb per plugin route and let VitNode assemble the trail for public pages and AdminCP screens.
VitNode renders a breadcrumb trail in both the AdminCP header and the public site layout. Every matched route contributes one crumb, parent to child:
Home / Catalog / Products / Laptops / MacBook ProSo a route says what it is called and nothing else. VitNode owns the separators,
the nav and aria-current semantics, and the locale-aware link to each
route's own URL—a plugin never builds a router link, and never restates the
crumbs of the layouts above it.
Quick start
A static, translated crumb
Declare a component on definePluginRoute. It renders inside the message
namespaces the route declared, so useTranslations just works:
import { definePluginRoute } from '@vitnode/core/routing'
import { useTranslations } from 'use-intl'
function ProductsBreadcrumb() {
const t = useTranslations('@acme/catalog')
return t('breadcrumbs.products')
}
export const route = definePluginRoute({
breadcrumb: ProductsBreadcrumb,
})A crumb read from the loader
The crumb is handed its own match's data, so a dynamic route can name itself with what it fetched—no second request, and no guessing from the URL:
import type { PluginRouteBreadcrumbProps } from '@vitnode/core/routing'
import { definePluginRoute } from '@vitnode/core/routing'
interface Category {
name: string
}
function CategoryBreadcrumb({
loaderData,
}: PluginRouteBreadcrumbProps<Category>) {
return loaderData.name
}
export const route = definePluginRoute({
load: async ({ params }) => await fetchCategory(params.categorySlug),
breadcrumb: CategoryBreadcrumb,
})PluginRouteBreadcrumbProps<TData, TSearch> carries loaderData, params and
search—the same three names the loader, head and the page component receive.
Leaving a route out
A route that declares no breadcrumb contributes nothing, and its parents' crumbs
stay exactly where they were. false says the same thing on purpose, which is
worth doing when a page's frame already names the screen:
export const route = definePluginRoute({
breadcrumb: false,
})Rules
| Declaration | What the trail does |
|---|---|
| A component | One crumb, given this route's loader data and params |
false | This route is left out; its parents' crumbs remain |
| Nothing at all | The same, said by omission |
| The last crumb | Rendered as the current page, not as a link |
| Every other crumb | A locale-aware link to that route's own URL |
AdminCP labels come from the navigation
An AdminCP screen's trail is named by the sidebar this administrator can actually see, so a plugin that adds a nav entry gets its label for free—in every language. Keep the route, the sidebar entry and the translations in the same package.
Return a label, not a trail
A crumb returns text or an element. Do not render a <Breadcrumb>, a
separator, or a link: the shell draws the trail above the page outlet and
needs each crumb as one item so it can put them in one navigation landmark.