SwBreadcrumb

SwBreadcrumb is a headless breadcrumb navigation: driven by an items array (first→last) of { name, to? }. Middle items with to render as SwLink (real <a>, SEO / a11y friendly); the last item = current page is always rendered as a non-clickable <span> + aria-current="page" (NN/g & Google breadcrumb guidance), even if a to is given.

schema is on by default — it calls useSchemaOrg(defineBreadcrumb(...)) from the same items to emit BreadcrumbList structured data, making the visible breadcrumb and the JSON-LD a single source of truth so the two never drift apart. When enabled, do not also hand-write defineBreadcrumb on the page.

Visuals follow the "minimal necessary baseline" (inline layout + separator + current-page emphasis); font size / color / hover are overridden by the applier.

Link color: breadcrumb links are rendered by SwLink and default to the primary color. To use a muted color, set the CSS variable --sw-link-color: var(--muted-foreground) on a container (cascades via the variable). Do not write .sw-link { color } (equal specificity gambles on CSS source order; dev/prod can flip).

Basic usage

Omit to on the last item to mark it the current page (you may still give to — used only for JSON-LD; it stays non-clickable):

Basic three-level breadcrumb

加载中...
<script setup lang="ts">
const crumbs = [
  { name: 'Home', to: '/' },
  { name: 'Shorts', to: '/shorts' },
  { name: 'Trending' },
]
</script>

<template>
  <SwBreadcrumb :items="crumbs" />
</template>

Custom separator

separator prop changes the separator text; the #separator slot can hold any content:

separator prop / #separator slot

加载中...

Custom item rendering

The #item slot fully takes over per-item rendering, exposing { item, isLast } in scope:

#item slot customization

加载中...

schema defaults to true: the component emits BreadcrumbList structured data from the same items (item = each entry's to, omitted when the last entry has no to). This keeps the visible breadcrumb and the structured data a single source of truth, avoiding the "page hand-writes defineBreadcrumb while the visible UI drifts" problem.

  • Pages using SwBreadcrumb (with schema on) must not also hand-write useSchemaOrg(defineBreadcrumb(...)), or output is duplicated.
  • When the page manages structured data itself, pass :schema="false" to render only the visible UI.

Props

NameTypeRequiredDefaultDescription
itemsSwBreadcrumbItem[]✓—Breadcrumb chain (first→last). Last item = current page, auto non-clickable + aria-current
schemabooleantrueAlso emit BreadcrumbList JSON-LD (single source with the visible UI). Don't hand-write defineBreadcrumb when on
separatorstring'/'Separator text (overridable via the #separator slot)
ariaLabelstring'面包屑'aria-label for the <nav>

SwBreadcrumbItem: { name: string; to?: string }. Omitting to = non-clickable; the last item is always the current page regardless of to (to only feeds the JSON-LD item).

Slots

NameScopeDescription
separator—Custom separator (overrides the separator prop)
item{ item, isLast }Custom per-item rendering. Falls back to default link / current-page rendering

Notes

  • Last item is always the current page: non-clickable + aria-current="page" (even with to), per NN/g / Google breadcrumb guidance.
  • Single source, no drift: when schema is on, the visible UI and JSON-LD come from one items; don't hand-write defineBreadcrumb on the page.
  • Link color: override the --sw-link-color variable; don't write .sw-link { color }.
  • No built-in visual brand: only minimal inline + separator + current-page styles; the rest is overridden by the applier (target .sw-breadcrumb).