Skip to content

vitepress-plugin-breadcrumbs

VitePress-style dynamic breadcrumbs built from the current page's position in the sidebar. Makes no assumption about content structure, so it fits any VitePress project.

Installation

bash
npm install @ampernic/vitepress-plugin-breadcrumbs

Concept

The full breadcrumb trail is composed as:

prefix  ->  home  ->  ancestor groups from the sidebar  ->  current page
  1. Every trail entry carries a link.
  2. The last crumb whose link matches the current route becomes the current one (so a document index/landing shows its own crumb as current); otherwise the current page is appended as a separate entry.
  3. Consecutive crumbs with the same link collapse (dedup).
  4. hideSingle then hides a lone crumb (for example, on a bare landing).

The sidebar path is looked up in themeConfig.sidebar (array, SidebarMulti and { base, items } groups are all supported). When the page is not found in the sidebar and fallback: 'path' is set, breadcrumbs are derived from URL segments.

Usage

Add the component to a layout slot (usually doc-before, above the page title):

ts
// .vitepress/theme/index.ts
import DefaultTheme from 'vitepress/theme'
import { h } from 'vue'
import Breadcrumbs from '@ampernic/vitepress-plugin-breadcrumbs/components/Breadcrumbs.vue'

export default {
  extends: DefaultTheme,
  Layout: () =>
    h(DefaultTheme.Layout, null, {
      'doc-before': () => h(Breadcrumbs),
    }),
}

Configuration

Globally via themeConfig.breadcrumbs or per-prop (props beat config, config beats defaults). The config can be typed with defineBreadcrumbsConfig:

ts
// .vitepress/config.ts
import { defineBreadcrumbsConfig } from '@ampernic/vitepress-plugin-breadcrumbs'

export default {
  themeConfig: {
    breadcrumbs: defineBreadcrumbsConfig({
      home: 'auto',
      separator: '>',
      hideSingle: true,
      fallback: 'path',
    }),
  },
}
OptionDefaultDescription
homefalseRoot crumb of the document (points at the landing/index of the document). false disables it; { text, link? } is a static crumb (link defaults to the computed landing); 'auto' links to the landing with text = homeText ?? site title ?? base slug; (ctx) => ({ text, link? }) | false is a resolver over BreadcrumbHomeCtx. On the index page itself it renders as the current (unlinked) crumb.
homeTextsite titleText for home: 'auto'
prefixfalseAncestor crumbs before home (for example, a cross-section site root and/or a distribution landing). BreadcrumbHome[] or (ctx) => BreadcrumbHome[]. A prefix crumb whose link matches the current page becomes the current one; consecutive duplicates by link collapse.
showOnHomefalseRender on layout: home pages as well, or when there is no document context, so prefix can show crumbs on the site root and on landings
separator'/'Separator between crumbs
showCurrentPagetrueAppend the current page as a final (unlinked) crumb
hideSingletrueRender nothing when the trail is one crumb or fewer
fallback'none''path' derives crumbs from the URL when the page is missing from the sidebar; 'none' renders nothing
class--Extra class on the root <nav>
ariaLabel'Breadcrumb'ARIA label for the landmark

Disable on a specific page via frontmatter:

yaml
---
breadcrumbs: false
---

Resolver context

home/prefix functions receive a BreadcrumbHomeCtx:

FieldDescription
pathRaw route path
segsPath segments without the base
baseSite base ('/', '/alt-server/', ...)
distroBase slug ('alt-server'); '' when the base is '/'
versionFirst segment when it looks like a version (1.2, 1.2.3, p11)
sidebarBaseComputed sidebar base ('/11.1/' or '')
landingLink to the document landing/index (site base + sidebar base)
siteTitleSite title from themeConfig
pageTitleCurrent page title

Example of a multi-level trail (site root -> distribution landing -> document index -> sidebar path -> current page):

ts
import type { BreadcrumbHomeCtx } from '@ampernic/vitepress-plugin-breadcrumbs'

breadcrumbs: defineBreadcrumbsConfig({
  showOnHome: true,
  hideSingle: false,
  home: (c: BreadcrumbHomeCtx) =>
    c.distro
      ? { text: c.version ? `${c.distro} ${c.version}` : c.distro, link: c.landing }
      : false,
  prefix: (c: BreadcrumbHomeCtx) => {
    const arr = [{ text: 'Home', link: '/' }]
    if (c.distro && c.version) arr.push({ text: c.distro, link: `/${c.distro}/` })
    return arr
  },
})

Styling

Styles are scoped and use VitePress CSS variables. Stable classes are available for overrides: .vp-breadcrumbs, .vp-breadcrumbs-list, .vp-breadcrumbs-item, .vp-breadcrumbs-link, .vp-breadcrumbs-current, .vp-breadcrumbs-sep.

License

GPL-3.0-or-later