Breadcrumb

The trail of pages leading to the current one, as links with separators.

Install

If this is the first component in the project, set up once. This writes ermine.json and copies the theme stylesheet. The installation guide covers Vue, Nuxt and Astro.

npx ermineui init
pnpm dlx ermineui init
yarn dlx ermineui init
bunx ermineui init

Then add the component:

npx ermineui add breadcrumb
pnpm dlx ermineui add breadcrumb
yarn dlx ermineui add breadcrumb
bunx ermineui add breadcrumb

That copies 3 files into src/components/ui/breadcrumb/, 1 helper into src/lib/ermine/. Files you already have are kept.

Use

import { Breadcrumb, BreadcrumbItem } from '@/components/ui/breadcrumb'
<Pagination v-model="page" :page-count="24" />

<Breadcrumb>
  <BreadcrumbItem href="/projects">Projects</BreadcrumbItem>
  <BreadcrumbItem :as="NuxtLink" to="/projects/storefront">Storefront</BreadcrumbItem>
  <BreadcrumbItem current>Deployments</BreadcrumbItem>
</Breadcrumb>

<Slider v-model="memory" :min="128" :max="3008" :step="64" />

<ToggleGroup v-model="period" aria-label="Period">  <!-- type="multiple" takes an array -->
  <ToggleGroupItem value="7d">7 days</ToggleGroupItem>
  <ToggleGroupItem value="30d">30 days</ToggleGroupItem>
</ToggleGroup>

In Nuxt, with the auto-import setting, the tags work in templates without the import. In Astro, use it inside a Vue island.

What gets copied

FileWhere it goes
Breadcrumb.vuesrc/components/ui/breadcrumb/Breadcrumb.vue
BreadcrumbItem.vuesrc/components/ui/breadcrumb/BreadcrumbItem.vue
index.tssrc/components/ui/breadcrumb/index.ts
primitive.ts helpersrc/lib/ermine/primitive.ts

The folders are the suggested ones. ermine.json says where yours are.

Source

This is exactly what the command copies. To install by hand, create each file below and the helpers listed above.

Breadcrumb.vue 72 lines
<script setup lang="ts">
withDefaults(
  defineProps<{
    /** Accessible name of the trail. */
    label?: string
  }>(),
  { label: 'Breadcrumb' },
)
</script>

<template>
  <nav class="er-breadcrumb" :aria-label="label">
    <ol><slot /></ol>
  </nav>
</template>

<style>
@layer components {
  .er-breadcrumb ol {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.375rem;
    margin: 0;
    padding: 0;
    color: var(--er-muted-foreground);
    font-size: 0.875rem;
    list-style: none;
  }

  .er-breadcrumb-item {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    min-width: 0;
  }

  /* The separator is drawn in CSS, so screen readers hear a plain list of links. */
  .er-breadcrumb-item + .er-breadcrumb-item::before {
    content: '';
    flex-shrink: 0;
    width: 0.875rem;
    height: 0.875rem;
    background: currentColor;
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m9 18 6-6-6-6'/%3E%3C/svg%3E")
      center / contain no-repeat;
    opacity: 0.7;
  }

  .er-breadcrumb-link {
    border-radius: var(--er-radius-sm);
    color: inherit;
    text-decoration: none;
    transition: color var(--er-duration);
  }

  a.er-breadcrumb-link:hover {
    color: var(--er-foreground);
  }

  .er-breadcrumb-link:focus-visible {
    outline: 2px solid var(--er-ring);
    outline-offset: 2px;
  }

  .er-breadcrumb-link[aria-current='page'] {
    color: var(--er-foreground);
    font-weight: var(--er-weight-medium);
  }
}
</style>
BreadcrumbItem.vue 24 lines
<script setup lang="ts">
import type { Component } from 'vue'
import { Primitive } from '../../lib/primitive'

defineOptions({ inheritAttrs: false })

withDefaults(
  defineProps<{
    /** Tag or component for the link, e.g. NuxtLink. Attributes such as href or to are passed on to it. */
    as?: string | Component
    /** The page the reader is on now: shown as plain text, not a link. */
    current?: boolean
  }>(),
  { as: 'a' },
)
</script>

<template>
  <li class="er-breadcrumb-item">
    <span v-if="current" class="er-breadcrumb-link" aria-current="page"><slot /></span>
    <Primitive v-else v-bind="$attrs" :as="as" class="er-breadcrumb-link"><slot /></Primitive>
  </li>
</template>
index.ts 4 lines
/** Breadcrumb — the trail of pages leading to the current one, as links with separators. */
export { default as Breadcrumb } from './Breadcrumb.vue'
export { default as BreadcrumbItem } from './BreadcrumbItem.vue'