Breadcrumb

Displays the path to the current resource using a hierarchy of links.

Examples

Basic

PropDefaultTypeDescription
items[]arrayAn array of Links wrapped around the Button component, inheriting all its props and slots with additional children prop.
Preview
Code

Variant & Color

PropDefaultTypeDescription
breadcrumb-activetext-primary{variant}-{color}The active breadcrumb variant and color.
breadcrumb-inactivetext-muted{variant}-{color}The inactive breadcrumb variant and color.
Preview
Code

Separator

PropDefaultTypeDescription
separatori-radix-icons-chevron-rightstringThe separator icon.
Preview
Code

Ellipsis

You can adjust the breadcrumb behavior dynamically with the BreadcrumbEllipsis. When there are children in the breadcrumb, the BreadcrumbEllipsis will appear as an icon, and upon clicking it, a DropdownMenu will open, allowing you to navigate to the child elements.

PropDefaultTypeDescription
ellipsisi-radix-icons-dots-horizontalstringThe ellipsis icon.
ConditionDefaultTypeDescription
children-arayAn array of children Links wrapped around the Button component
Preview
Code

Size

Adjust the breadcrumb size without limits. Use breakpoints (e.g., sm:sm, xs:lg) for responsive sizes or states (e.g., hover:lg, focus:3xl) for state-based sizes.

PropDefaultTypeDescription
sizesmstringAdjusts the overall size of the breadcrumb component.
_breadcrumbLink.sizesmstringCustomizes the size of each breadcrumb link.
_breadcrumbSeparator.sizesmstringModifies the size of the breadcrumb separator.
Preview
Code

Slots

NamePropsDescription
defaultitem index isActiveThe breadcrumb item
separatoritemThe separator
rootitemsThe root breadcrumb
listitemThe list of items
dropdownitemThe dropdown if available ellipsis
Preview
Code

Presets

shortcuts/breadcrumb.ts
type BreadcrumbPrefix = 'breadcrumb'

export const staticBreadcrumb: Record<`${BreadcrumbPrefix}-${string}` | BreadcrumbPrefix, string> = {
  // config
  'breadcrumb': '',
  'breadcrumb-active': 'breadcrumb-active-text-primary',
  'breadcrumb-inactive': 'breadcrumb-inactive-text-muted',
  'breadcrumb-separator-icon': 'i-radix-icons-chevron-right',
  'breadcrumb-ellipsis-icon': 'i-radix-icons-dots-horizontal',

  // components
  'breadcrumb-root': '',
  'breadcrumb-list': 'flex flex-wrap items-center break-words text-muted',
  'breadcrumb-link': 'transition-colors font-normal px-1.5 sm:px-2.5',
  'breadcrumb-item': 'inline-flex items-center gap-1.5',
  'breadcrumb-separator': 'flex',

  // TODO
  'breadcrumb-ellipsis': 'flex items-center justify-center px-1.5 sm:px-2.5 cursor-pointer',
}

export const dynamicBreadcrumb = [
  // states
  [
    /^breadcrumb-active-([^-]+)-([^-]+)$/,
    ([, variant = 'text', color = 'primary']) =>
      `data-[state=active]:btn-${variant}-${color}`,
  ],
  [
    /^breadcrumb-inactive-([^-]+)-([^-]+)$/,
    ([, variant = 'text', color = 'muted']) =>
      `data-[state=inactive]:btn-${variant}-${color}`,
  ],
]

export const breadcrumb = [
  ...dynamicBreadcrumb,
  staticBreadcrumb,
]

Props

types/breadcrumb.ts
import type { HTMLAttributes } from 'vue'
import type { NButtonProps } from './button'

interface BaseExtensions { class?: HTMLAttributes['class'] }

type BreadcrumbListItem = NButtonProps & {
  children?: NButtonProps[]
}

export interface NBreadcrumbProps extends BaseExtensions, Pick<NBreadcrumbLinkProps, 'breadcrumbActive' | 'breadcrumbInactive'> {
  /**
   * List of items to display in the breadcrumb.
   *
   * @example
   * items: [{ label: 'Home', to: '/' }, { label: 'About', to: '/about' }]
   */
  items: Partial<BreadcrumbListItem>[]
  separator?: NBreadcrumbSeparatorProps['icon']
  ellipsis?: NBreadcrumbEllipsisProps['icon']
  /**
   * Allows you to change the size of the input.
   *
   * @default sm
   *
   * @example
   * size="sm" | size="2cm" | size="2rem" | size="2px"
   */
  size?: string

  // maxItems?: number

  // sub-components
  _breadcrumbSeparator?: Partial<NBreadcrumbSeparatorProps>
  _breadcrumbItem?: Partial<NBreadcrumbItemProps>
  _breadcrumbRoot?: Partial<NBreadcrumbRootProps>
  _breadcrumbList?: Partial<NBreadcrumbListProps>
  _breadcrumbLink?: Partial<NBreadcrumbLinkProps>
  _breadcrumbEllipsis?: Partial<NBreadcrumbEllipsisProps>

  /**
   * `UnaUI` preset configuration
   *
   * @see https://github.com/una-ui/una-ui/blob/main/packages/preset/src/_shortcuts/breadcrumb.ts
   */
  una?: NBreadcrumbUnaProps
}

export interface NBreadcrumbRootProps extends BaseExtensions {
  una?: Pick<NBreadcrumbUnaProps, 'breadcrumbRoot'>
}

export interface NBreadcrumbItemProps extends BaseExtensions {
  /**
   * `UnaUI` preset configuration
   *
   * @see https://github.com/una-ui/una-ui/blob/main/packages/preset/src/_shortcuts/breadcrumb.ts
   */
  una?: Pick<NBreadcrumbUnaProps, 'breadcrumbItem'>
}

export interface NBreadcrumbSeparatorProps extends BaseExtensions {
  /**
   * Custom separator icon.
   */
  icon?: string
  /**
   * Allows you to change the size of the input.
   *
   * @default sm
   *
   * @example
   * size="sm" | size="2cm" | size="2rem" | size="2px"
   */
  size?: string
  /**
   * `UnaUI` preset configuration
   *
   * @see https://github.com/una-ui/una-ui/blob/main/packages/preset/src/_shortcuts/breadcrumb.ts
   */
  una?: Pick<NBreadcrumbUnaProps, 'breadcrumbSeparator' | 'breadcrumbSeparatorIcon'>
}

export interface NBreadcrumbListProps extends BaseExtensions {
  /**
   * `UnaUI` preset configuration
   *
   * @see https://github.com/una-ui/una-ui/blob/main/packages/preset/src/_shortcuts/breadcrumb.ts
   */
  una?: Pick<NBreadcrumbUnaProps, 'breadcrumbList'>
}

export interface NBreadcrumbLinkProps extends BaseExtensions, NButtonProps {
  active?: boolean
  breadcrumbActive?: string
  breadcrumbInactive?: string
}

export interface NBreadcrumbEllipsisProps extends BaseExtensions {
  /**
   * Custom separator icon.
   */
  icon?: string
  /**
   *  /**
   * Allows you to change the size of the input.
   *
   * @default sm
   *
   * @example
   * size="sm" | size="2cm" | size="2rem" | size="2px"
   */
  size?: string
  /**
   * `UnaUI` preset configuration
   *
   * @see https://github.com/una-ui/una-ui/blob/main/packages/preset/src/_shortcuts/breadcrumb.ts
   */
  una?: Pick<NBreadcrumbUnaProps, 'breadcrumbEllipsis' | 'breadcrumbEllipsisIcon'>
}

interface NBreadcrumbUnaProps {
  breadcrumb?: HTMLAttributes['class']
  breadcrumbRoot?: HTMLAttributes['class']
  breadcrumbItem?: HTMLAttributes['class']
  breadcrumbEllipsis?: HTMLAttributes
  breadcrumbEllipsisIcon?: HTMLAttributes['class']
  breadcrumbList?: HTMLAttributes['class']
  breadcrumbSeparator?: HTMLAttributes['class']
  breadcrumbSeparatorIcon?: HTMLAttributes['class']
}

Components

Breadcrumb.vue
BreadcrumbRoot.vue
BreadcrumbList.vue
BreadcrumbLink.vue
BreadcrumbItem.vue
BreadcrumbSeparator.vue
BreadcrumbEllipsis.vue
<script lang="ts" setup>
import type { NBreadcrumbProps } from '../../../types'
import { cn } from '../../../utils'
import DropdownMenu from '../../elements/dropdown-menu/DropdownMenu.vue'
import BreadcrumbEllipsis from './BreadcrumbEllipsis.vue'
import BreadcrumbItem from './BreadcrumbItem.vue'
import BreadcrumbLink from './BreadcrumbLink.vue'
import BreadcrumbList from './BreadcrumbList.vue'
import BreadcrumbRoot from './BreadcrumbRoot.vue'
import BreadcrumbSeparator from './BreadcrumbSeparator.vue'

const props = defineProps<NBreadcrumbProps>()
</script>

<template>
  <BreadcrumbRoot
    :class="cn(
      'breadcrumb',
      props.class,
      props.una?.breadcrumb,
    )"
    :una
    :size
    v-bind="_breadcrumbRoot"
  >
    <slot name="root" :items="items">
      <BreadcrumbList
        :una
        :size
        v-bind="_breadcrumbList"
      >
        <template
          v-for="(item, i) in items"
          :key="i"
        >
          <slot name="list" :item="item">
            <BreadcrumbItem
              :una
              :size
              v-bind="_breadcrumbItem"
            >
              <slot name="item" :item="item">
                <BreadcrumbLink
                  v-if="!item.children?.length"
                  :active="i === items.length - 1"
                  :breadcrumb-active="props.breadcrumbActive"
                  :breadcrumb-inactive="props.breadcrumbInactive"
                  :size
                  v-bind="{
                    ...item,
                    ..._breadcrumbLink,
                  }"
                >
                  <slot :item="item" :index="i" :is-active="i === items.length - 1" />
                </BreadcrumbLink>
                <template v-else>
                  <slot name="dropdown" :item="item">
                    <DropdownMenu
                      :size
                      :modal="false"
                      :items="item.children"
                      :_dropdown-menu-item="{
                        ..._breadcrumbLink,
                      }"
                    >
                      <BreadcrumbEllipsis
                        :size
                        :icon="ellipsis"
                        v-bind="_breadcrumbEllipsis"
                      />
                    </DropdownMenu>
                  </slot>
                </template>
              </slot>
            </BreadcrumbItem>
            <BreadcrumbSeparator
              v-if="i < props.items!.length - 1"
              :icon="props.separator"
              :size
              :una
              v-bind="_breadcrumbSeparator"
            >
              <slot name="separator" />
            </BreadcrumbSeparator>
          </slot>
        </template>
      </BreadcrumbList>
    </slot>
  </BreadcrumbRoot>
</template>