Skip to content
FunCoding

vue-breadcrumb

Give a Vue SPA route its breadcrumb, entirely from the router file. The breadcrumb component reads four declarations in `meta` — `showBreadcrumb`, `breadcrumb`, `breadcrumbParents` and `breadcrumbResource` — and knows no page by name. Auto-invoke when: the user adds a route to any file in `assets/vue/router/`, creates a new Vue page or view that needs a URL, migrates a legacy PHP page to Vue, reports a wrong or missing breadcrumb, sees the console warning "[Breadcrumb] Route ... has no meta.breadcrumb", or mentions breadcrumb, crumb, trail, `meta.breadcrumb`, `breadcrumbParents` or `breadcrumbResource`. Do NOT invoke for: the legacy PHP breadcrumb (`window.breadcrumb`, injected by `public/main/`), for `/admin/settings/<namespace>` (its last crumb is read from the DOM), or for styling work on `Breadcrumb.vue` itself.

Star
1,011
License
GPL-3.0
Last commit
Oct 13, 2026

.claude/skills/vue-breadcrumb/SKILL.md

View on GitHub

Never edit assets/vue/components/Breadcrumb.vue to give a page its trail. The component holds no page name and no path. Everything a trail needs is declared in the route.

The three steps that always apply

1. Ask for a breadcrumb

Set showBreadcrumb: true in the meta of the parent route. Without it, App.vue does not mount the component and nothing you declare below has any effect.

A route that only sometimes has a trail declares a function instead. It receives the route:

// The personal agenda hangs from no course, so it has nothing to show.
showBreadcrumb: (route) => Number(route.query?.cid || 0) > 0,

2. Declare the label

Set meta.breadcrumb on the parent and on every leaf. The value is a translation key, never translated text.

export default {
  path: "/resources/checklist/:node/",
  meta: {
    requiresAuth: true,
    showBreadcrumb: true,
    tool: "checklist",
    breadcrumb: "Checklists",
  },
  name: "checklist",
  component: () => import("../components/layout/SimpleRouterViewLayout.vue"),
  redirect: { name: "ChecklistList" },
  children: [
    { name: "ChecklistList", path: "", meta: { breadcrumb: "" }, component: ... },
    { name: "ChecklistCreate", path: "create", meta: { breadcrumb: "Create" }, component: ... },
    { name: "ChecklistUpdate", path: "edit/:id", meta: { breadcrumb: "Edit" }, component: ... },
  ],
}

breadcrumb: "" means omit this crumb, and it is what a list page usually wants: the tool crumb already names that page. An absent property is a different thing — it triggers the development warning and shows the raw route name.

The label can also be a function returning a key, when it depends on the request:

breadcrumb: (route) => {
  const gid = Number(route.query?.gid || 0)
  const cid = Number(route.query?.cid || 0)

  return gid > 0 ? "Group agenda" : cid > 0 ? "Agenda" : "Personal agenda"
},

A function may also return "" to omit the crumb, but only on a route that declares breadcrumbParents: the tool and resource branches still compare the raw meta.breadcrumb property, so there a function is never empty. Declare it when the page's own name exists for some requests only. AdminStatistics in assets/vue/router/admin.js is the reference — its key comes from activeReportLabelKey (assets/vue/utils/statisticsReports.js), which names the report in route.query.report and returns "" when there is none.

3. Register every key

A key that is new to the platform goes by hand into three files:

  • assets/locales/en_US.json
  • translations/messages.pot
  • translations/messages.en_US.po

php bin/console chamilo:update_vue_translations does not create keys. It only propagates to the other locales the keys that en_US.json already holds. Never commit a mass regeneration of assets/locales/*.json; a single new line is fine.

Check first whether the key exists — most tool names already do:

python3 -c "import json; d=json.load(open('assets/locales/en_US.json')); print('Checklists' in d)"

The two extra declarations

Give the leaf the fixed ancestors that always precede it. Each entry is { label, route }, where label is a translation key and route is a Vue Router location — prefer { name: ... } over a raw path.

meta: {
  breadcrumb: "Import checklists",
  breadcrumbParents: [
    { label: "Administration", route: { name: "AdminIndex" } },
    { label: "Checklists", route: { name: "ChecklistAdminList" } },
  ],
}

When several routes share the same ancestors, declare the lists once at the top of the file. assets/vue/router/admin.js is the reference, with adminCrumb, classesCrumbs, multiUrlCrumbs and accessUrlCrumbs; room.js and branch.js show the smaller shape.

A route with breadcrumbParents owns its whole trail and takes the first branch of buildBreadcrumb, so nothing else runs for it.

The ancestors are fixed, but the leaf's own crumb is not: an empty key drops it and leaves the ancestors standing. That is how a page hangs a report or filter name off a parent that links back to its own bare URL, and it is the only branch where a function may return "".

Declare it on the parent, when the trail has to name the thing the user opened.

// One resource at a time: list -> resource -> sub-page.
breadcrumbResource: {
  trail: "self",
  listRoute: "AssignmentsList",
  detailRoute: "AssignmentDetail",
  detailParam: "id",
}

// A chain of folders, walked up the resource-node parents.
breadcrumbResource: {
  trail: "ancestors",
  listRoute: "DocumentsList",
  detailRoute: "DocumentsList",
}

This declaration also drives the fetch: loadResourceNodeIfNeeded loads the resource node only for a route whose tool declares it. Nothing else has to be wired.

Do not do these

  • Do not add a rule to Breadcrumb.vue. If a trail seems to need one, the shape is probably already covered by one of the four declarations. Read the component's own builders first. A rule that names a page or a route never belongs there. Widening a contract the declarations already document is a different thing, and rare: do it only when a builder fails to honour a declaration the skill already describes.
  • Do not match route names by substring. A rule like route.name.includes("Page") puts a "Pages" crumb on every wiki page of every course.
  • Do not pass translated text as a label. The component calls t() on what you declare.
  • Do not expect a one-crumb trail to appear. The component gives the first crumb to the PrimeVue home slot, and the container is hidden while the rest is empty. A page whose trail reduces to its tool shows nothing.

Verify

# Fails when a route renders a breadcrumb without declaring its label.
yarn check:breadcrumb-routes

npx eslint assets/vue/router/
yarn dev

Then open the page and read the browser console. [Breadcrumb] Route "X" has no meta.breadcrumb means a declaration is missing. The warning is stripped from the production bundle.

Cover it

tests/playwright/features/breadcrumb.feature holds the breadcrumb scenarios. Add yours there.

Assert on CSS selectors, never on crumb text: this platform runs in many languages and the test environment is not always English.

Then I should see the ".app-breadcrumb a[href='/admin/urls']" element

An a[href] proves both that the ancestor is there and that it points at the right place. Two traps that cost real time:

  • The last crumb is a <span>, not a link. Asserting a[href] on the current page's own crumb never matches. Assert on an ancestor.
  • A tool with breadcrumbResource paints late. It waits for the resource-node fetch, well past Playwright's 15 s default. Use I wait up to 45 seconds for the element ... to appear.

Playwright needs BASE_URL=http://localhost inside the container, and the generated spec under tests/playwright/.features-gen/ is tracked, so run bddgen and commit it too.

Similar Skills

prototype

MAmattpocock/skills288k10,178 new stars in the last 7 days

angular-developer

AFaffaan-m/ECC278k4,046 new stars in the last 7 days

Official

firecrawl-build-scrape

FIfirecrawl/firecrawl191k2,010 new stars in the last 7 days

Featured

frontend-design

Set visual direction and typography for UI, avoiding templated defaults.

ANanthropics/skills181k1,119 new stars in the last 7 days

Featured

theme-factory

Apply color and font themes to slides, docs and web pages, with 10 built-in themes.

ANanthropics/skills181k1,119 new stars in the last 7 days

Featured

web-artifacts-builder

Build complex HTML artifacts with React, Tailwind CSS, state management and routing.

ANanthropics/skills181k1,119 new stars in the last 7 days