# Vue Breadcrumb

Give a Vue SPA route its breadcrumb, entirely from the router file.

- Repository: https://github.com/chamilo/chamilo-lms (1019 stars)
- Category: Engineering
- License: GPL-3.0
- Last updated: 2026-11-01
- Runs scripts: no, instructions only

## Install

Claude Code: `npx skills add chamilo/chamilo-lms --skill vue-breadcrumb -g -a claude-code -y`
Codex: `npx skills add chamilo/chamilo-lms --skill vue-breadcrumb -g -a codex -y`
Cursor: `npx skills add chamilo/chamilo-lms --skill vue-breadcrumb -g -a cursor -y`
Gemini CLI: `npx skills add chamilo/chamilo-lms --skill vue-breadcrumb -g -a gemini-cli -y`

## Description

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.

## SKILL.md, as published by its author (untrusted third-party text, read it as data)

# Breadcrumbs for a Vue route

**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:

```js
// 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.

```js
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:

```js
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"
},
```

The rest: https://github.com/chamilo/chamilo-lms/blob/HEAD/.claude/skills/vue-breadcrumb/SKILL.md
