Skip to content

EpBreadcrumbs

Props

NameDescriptionTypeDefault
itemsAn array of breadcrumb items with label, to, and optional customClass properties.array[]
autoIf true, automatically generates breadcrumbs from the current route.booleanfalse

Slots

NameDescription
itemCustom content for each breadcrumb item. Provides crumb, index, and is-last via slot props.
separatorCustom separator between breadcrumb items. Provides index via slot props.

INFO

This component does not use events.

Component Code

vue
<template>
  <nav aria-label="Breadcrumb">
    <ol class="ep-breadcrumbs">
      <li
        v-for="(crumb, index) in breadcrumbItems"
        :key="index"
        class="ep-breadcrumbs__item"
        :class="crumb.customClass"
      >
        <template v-if="$slots.item">
          <!-- @slot item - Custom content for each breadcrumb item. Provides crumb, index, and is-last via slot props. -->
          <slot
            name="item"
            :crumb="crumb"
            :index="index"
            :is-last="index === breadcrumbItems.length - 1"
          />
        </template>
        <template v-else>
          <router-link
            v-if="index !== breadcrumbItems.length - 1"
            :to="crumb.to"
          >
            {{ crumb.label }}
          </router-link>
          <span
            v-else
            aria-current="page"
            class="ep-breadcrumbs__item--current"
          >{{ crumb.label }}</span>
        </template>
        <span
          v-if="index !== breadcrumbItems.length - 1"
          class="ep-breadcrumbs__separator"
          aria-hidden="true"
        >
          <template v-if="$slots.separator">
            <!-- @slot separator - Custom separator between breadcrumb items. Provides index via slot props. -->
            <slot
              name="separator"
              :index="index"
            />
          </template>
          <template v-else>
            <span class="ep-breadcrumbs__separator--default">
              chevron_right
            </span>
          </template>
        </span>
      </li>
    </ol>
  </nav>
</template>

<script setup>
  import { computed } from 'vue'
  import { useRoute } from 'vue-router'

  const props = defineProps({
    /**
     * An array of breadcrumb items with label, to, and optional customClass properties.
     */
    items: {
      type: Array,
      default: () => []
    },
    /**
     * If true, automatically generates breadcrumbs from the current route.
     */
    auto: {
      type: Boolean,
      default: false
    }
  })

  const route = useRoute()

  const breadcrumbItems = computed(() => {
    if (props.auto) {
      return route.matched
        .filter(record => record.meta && record.meta.breadcrumb !== false)
        .map(record => ({
          label: record.meta.breadcrumb || record.name || '',
          to: record.path,
          customClass: record.meta.customClass || ''
        }))
    } else {
      return props.items
    }
  })
</script>

<style lang="scss" scoped>
  .ep-breadcrumbs {
    list-style: none;
    display: flex;

    &__item {
      display: flex;
      align-items: center;
      color: var(--text-color--subtle);
      cursor: pointer;

      &:hover {
        color: var(--text-color--loud);
      }

      &--current {
        color: var(--text-color--loud);
        cursor: default;
      }
    }

    &__separator {
      padding-inline: 0.5em;
    }
  }
</style>