@todovue/tv-breadcrumbs
v1.1.3
Published
A simple and customizable Vue 3 breadcrumbs component for your applications.
Maintainers
Readme
TODOvue Breadcrumbs (TvBreadcrumbs)
A flexible, framework‑agnostic Vue 3 breadcrumb navigation component with auto-generation from routes, custom separators, max items control, and full customization. Works seamlessly in Single Page Apps or Server-Side Rendered (SSR) environments (e.g. Nuxt 3).
Demo: https://ui.todovue.blog/breadcrumbs
Table of Contents
- Features
- Installation
- Quick Start (SPA)
- Nuxt 4 / SSR Usage
- Component Registration Options
- Props
- Events
- Slots
- Auto-Generate Mode
- Max Items & Ellipsis
- Router Integration
- Customization (Styles / Theming)
- Accessibility
- SSR Notes
- Development
- Contributing
- License
Features
- Manual items: Provide a static array of breadcrumb items
- Auto-generation: Automatically generate breadcrumbs from Vue Router routes
- Max items control: Collapse long breadcrumb trails with ellipsis (
…) - Custom separators: Choose your own separator character or component
- Customizable slots: Override item, current item, and separator rendering
- Router integration: Automatically integrates with Vue Router for navigation
- Accessibility: Full ARIA support with semantic HTML and structured data
- SSR-ready: Works in both SPA and SSR (Nuxt 3) contexts
- Lightweight: Tree-shakeable with Vue marked external in library build
Installation
Using npm:
npm install @todovue/tv-breadcrumbsUsing yarn:
yarn add @todovue/tv-breadcrumbsUsing pnpm:
pnpm add @todovue/tv-breadcrumbsQuick Start (SPA)
Global registration (main.js / main.ts):
import { createApp } from 'vue'
import App from './App.vue'
import { TvBreadcrumbs } from '@todovue/tv-breadcrumbs'
import '@todovue/tv-breadcrumbs/style.css' // import styles
createApp(App)
.use(TvBreadcrumbs) // enables <TvBreadcrumbs /> globally
.mount('#app')Local import inside a component:
<script setup>
import { TvBreadcrumbs } from '@todovue/tv-breadcrumbs'
const items = [
{ label: 'Home', href: '/' },
{ label: 'Products', href: '/products' },
{ label: 'Category', href: '/products/category' },
{ label: 'Item Details' }
]
function onItemClick({ item, index, event }) {
console.log('Clicked:', item.label)
}
</script>
<template>
<TvBreadcrumbs :items="items" @item-click="onItemClick" />
</template>Nuxt 4 / SSR Usage
First, add the stylesheet to your Nuxt config:
// nuxt.config.ts
export default defineNuxtConfig({
modules: [
'@todovue/tv-breadcrumbs/nuxt'
]
})Then create a plugin file: plugins/tv-breadcrumbs.client.ts (or without .client suffix as it's SSR-safe):
import { defineNuxtPlugin } from '#app'
import { TvBreadcrumbs } from '@todovue/tv-breadcrumbs'
export default defineNuxtPlugin(nuxtApp => {
nuxtApp.vueApp.use(TvBreadcrumbs)
})Use anywhere:
<TvBreadcrumbs auto-generate />Optional direct import (no plugin):
<script setup>
import { TvBreadcrumbs } from '@todovue/tv-breadcrumbs'
</script>Component Registration Options
| Approach | When to use |
|---------------------------------------------------------------------------------|------------------------------------------------|
| Global via app.use(TvBreadcrumbs) | Many usages across app / design system install |
| Local named import { TvBreadcrumbs } | Isolated / code-split contexts |
| Direct default import import { TvBreadcrumbs } from '@todovue/tv-breadcrumbs' | Single usage or manual registration |
Props
| Prop | Type | Default | Description |
|--------------|---------|----------------|--------------------------------------------------------------------------------------------------|
| items | Array | [] | Array of breadcrumb items. Each item: { label, href?, disabled?, key? }. |
| separator | String | '›' | Character or string to display between breadcrumb items. |
| maxItems | Number | 0 | Maximum items to display. If exceeded, shows first item + ellipsis + last N items. 0 = no limit. |
| autoGenerate | Boolean | false | Auto-generate breadcrumbs from $route.path or route meta (breadcrumb). |
| homeLabel | String | 'Home' | Label for the home item when auto-generating breadcrumbs. |
| activeLink | Boolean | false | If true, the current page item (last item) is rendered as a link. |
| ariaLabel | String | 'Breadcrumb' | ARIA label for the <nav> element. |
Item Object Structure
Each item in the items array can have:
{
label: string // Display text (required)
href?: string // Link URL (optional, null for current page)
icon?: string // Icon CSS class (e.g. "fa-solid fa-home") (optional)
disabled?: boolean // Disable interaction (optional)
key?: string // Unique key for rendering (optional, auto-generated if not provided)
}Events
| Event name (kebab) | Payload | Description |
|--------------------|--------------------------|-----------------------------------------------------------------------|
| item-click | { item, index, event } | Emitted when any breadcrumb item is clicked. |
| navigate | { to, item, index } | Emitted when navigation occurs via Vue Router (if router is present). |
Usage:
<TvBreadcrumbs
:items="items"
@item-click="handleClick"
@navigate="handleNavigate"
/>function handleClick({ item, index, event }) {
console.log('Clicked item:', item.label, 'at index:', index)
}
function handleNavigate({ to, item, index }) {
console.log('Navigating to:', to)
}Slots
The component provides three slots for full customization:
item slot
Customize the rendering of each breadcrumb link (except the last one).
<TvBreadcrumbs :items="items">
<template #item="{ item, index }">
<strong>{{ item.label }}</strong>
</template>
</TvBreadcrumbs>current slot
Customize the rendering of the current (last) breadcrumb item.
<TvBreadcrumbs :items="items">
<template #current="{ item, index }">
<em>{{ item.label }}</em>
</template>
</TvBreadcrumbs>separator slot
Customize the separator between breadcrumb items.
<TvBreadcrumbs :items="items">
<template #separator>
<span> / </span>
</template>
</TvBreadcrumbs>Auto-Generate Mode
When autoGenerate is enabled, the component automatically creates breadcrumbs from your current route.
Basic Auto-Generation
<TvBreadcrumbs auto-generate />This reads $route.path and creates breadcrumb items. For example:
- Path:
/docs/guides/installation - Result:
Home › Docs › Guides › Installation
Custom Home Label
<TvBreadcrumbs auto-generate home-label="Dashboard" />Route Meta Integration
You can define breadcrumbs in your route configuration:
const routes = [
{
path: '/products',
meta: {
breadcrumb: 'Products'
}
},
{
path: '/products/:id',
meta: {
breadcrumb: (route) => [
{ label: 'Products', href: '/products' },
{ label: route.params.id }
]
}
}
]The component will use:
- Route meta
breadcrumbif defined (string, array, or function) - Fallback to auto-generated path segments if no meta found
Max Items & Ellipsis
Control long breadcrumb trails with the maxItems prop:
<TvBreadcrumbs :items="longItemsList" :max-items="4" />Example:
- Original:
Home › Docs › API › v1 › Auth › Scopes - With
max-items="4":Home › … › Auth › Scopes
The algorithm keeps:
- First item (always visible)
- Ellipsis (
…) which is interactive: click to show hidden items in a dropdown - Last N-1 items (where N = maxItems)
Router Integration
TvBreadcrumbs automatically detects and integrates with Vue Router:
- Automatic navigation: Clicks on breadcrumb links call
router.push()instead of native navigation - Route reading: Accesses
$routefor auto-generation - Navigate event: Emits when programmatic navigation occurs
Without router: Links work as standard <a> tags with href.
With router: Navigation is handled programmatically, and the navigate event fires.
Customization (Styles / Theming)
The component uses scoped styles with BEM-like class names for easy customization:
CSS Classes
.tv-breadcrumb-root: Main<nav>container.tv-breadcrumb-list:<ol>list wrapper.tv-breadcrumb-item: Each<li>item.tv-breadcrumb-item--link: Non-current items.tv-breadcrumb-item--current: Current (last) item.tv-breadcrumb-item--disabled: Disabled items
.tv-breadcrumb-link:<a>link element.tv-breadcrumb-current: Current item<span>.tv-breadcrumb-separator: Separator<span>
Custom Styling Example
/* Override default styles */
.tv-breadcrumb-list {
font-size: 14px;
color: #333;
}
.tv-breadcrumb-link {
color: #0066cc;
text-decoration: none;
}
.tv-breadcrumb-link:hover {
text-decoration: underline;
}
.tv-breadcrumb-separator {
margin: 0 8px;
color: #999;
}
.tv-breadcrumb-current {
font-weight: 600;
color: #000;
}Accessibility
TvBreadcrumbs follows WAI-ARIA best practices:
- Semantic HTML: Uses
<nav>,<ol>,<li>for proper structure - ARIA attributes:
aria-labelon<nav>(customizable via prop)aria-current="page"on the current itemaria-disabledon disabled itemsaria-hiddenon separator
- Structured data: Implements Schema.org
ListItemmarkup for search engines - Keyboard navigation: All interactive elements are focusable and keyboard-accessible
- Screen reader friendly: Proper semantic structure and ARIA labels
SSR Notes
- No direct DOM (
window/document) access → safe for SSR - Router access is wrapped with safe guards (checks for
$route/$routerexistence) - Works with Nuxt 3 out of the box
- Styles are automatically injected when importing the component
- Auto-generation mode gracefully handles missing router in SSR context
Development
git clone https://github.com/TODOvue/tv-breadcrumbs.git
cd tv-breadcrumbs
npm install
npm run dev # run demo playground
npm run build # build libraryLocal demo served from Vite using index.html + src/demo examples.
Contributing
PRs and issues welcome. See CONTRIBUTING.md and CODE_OF_CONDUCT.md.
License
MIT © TODOvue
Attributions
Crafted for the TODOvue component ecosystem
