Breadcrumb

GitHub
A hierarchy of links to navigate through a website.

Usage

Use the Breadcrumb component to show the current page's location in your site's hierarchy.

<script setup lang="ts">
import type { BreadcrumbItem } from '@nuxt/ui'

const items = ref<BreadcrumbItem[]>([
  {
    label: 'Docs',
    icon: 'i-lucide-book-open',
    to: '/docs'
  },
  {
    label: 'Components',
    icon: 'i-lucide-box',
    to: '/docs/components'
  },
  {
    label: 'Breadcrumb',
    icon: 'i-lucide-link',
    to: '/docs/components/breadcrumb'
  }
])
</script>

<template>
  <UBreadcrumb :items="items" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { BreadcrumbItem } from '@nuxt/ui'

const items = ref<BreadcrumbItem[]>([
  {
    label: 'Docs',
    icon: 'i-lucide-book-open',
    to: '/docs'
  },
  {
    label: 'Components',
    icon: 'i-lucide-box',
    to: '/docs/components'
  },
  {
    label: 'Breadcrumb',
    icon: 'i-lucide-link',
    to: '/docs/components/breadcrumb'
  }
])
</script>

<template>
  <UBreadcrumb :items="items" />
</template>

Items

Use the items prop as an array of objects with the following properties:

  • label?: string
  • icon?: string
  • avatar?: AvatarProps
  • slot?: string
  • class?: any
  • ui?: { item?: ClassNameValue, link?: ClassNameValue, linkLeadingIcon?: ClassNameValue, linkLeadingAvatar?: ClassNameValue, linkLabel?: ClassNameValue, separator?: ClassNameValue, separatorIcon?: ClassNameValue }

You can pass any property from the Link component such as to, target, etc.

<script setup lang="ts">
import type { BreadcrumbItem } from '@nuxt/ui'

const items = ref<BreadcrumbItem[]>([
  {
    label: 'Docs',
    icon: 'i-lucide-book-open',
    to: '/docs'
  },
  {
    label: 'Components',
    icon: 'i-lucide-box',
    to: '/docs/components'
  },
  {
    label: 'Breadcrumb',
    icon: 'i-lucide-link',
    to: '/docs/components/breadcrumb'
  }
])
</script>

<template>
  <UBreadcrumb :items="items" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { BreadcrumbItem } from '@nuxt/ui'

const items = ref<BreadcrumbItem[]>([
  {
    label: 'Docs',
    icon: 'i-lucide-book-open',
    to: '/docs'
  },
  {
    label: 'Components',
    icon: 'i-lucide-box',
    to: '/docs/components'
  },
  {
    label: 'Breadcrumb',
    icon: 'i-lucide-link',
    to: '/docs/components/breadcrumb'
  }
])
</script>

<template>
  <UBreadcrumb :items="items" />
</template>
A span is rendered instead of a link when the to property is not defined.

Separator Icon

Use the separator-icon prop to customize the Icon between each item. Defaults to i-lucide-chevron-right.

<script setup lang="ts">
import type { BreadcrumbItem } from '@nuxt/ui'

const items = ref<BreadcrumbItem[]>([
  {
    label: 'Docs',
    icon: 'i-lucide-book-open',
    to: '/docs'
  },
  {
    label: 'Components',
    icon: 'i-lucide-box',
    to: '/docs/components'
  },
  {
    label: 'Breadcrumb',
    icon: 'i-lucide-link',
    to: '/docs/components/breadcrumb'
  }
])
</script>

<template>
  <UBreadcrumb separator-icon="i-lucide-arrow-right" :items="items" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { BreadcrumbItem } from '@nuxt/ui'

const items = ref<BreadcrumbItem[]>([
  {
    label: 'Docs',
    icon: 'i-lucide-book-open',
    to: '/docs'
  },
  {
    label: 'Components',
    icon: 'i-lucide-box',
    to: '/docs/components'
  },
  {
    label: 'Breadcrumb',
    icon: 'i-lucide-link',
    to: '/docs/components/breadcrumb'
  }
])
</script>

<template>
  <UBreadcrumb separator-icon="i-lucide-arrow-right" :items="items" />
</template>
You can customize this icon globally in your app.config.ts under ui.icons.chevronRight key.
You can customize this icon globally in your vite.config.ts under ui.icons.chevronRight key.

Color Soon

Use the color prop to change the color of the active Breadcrumb.

<script setup lang="ts">
import type { BreadcrumbItem } from '@nuxt/ui'

const items = ref<BreadcrumbItem[]>([
  {
    label: 'Docs',
    icon: 'i-lucide-book-open',
    to: '/docs'
  },
  {
    label: 'Components',
    icon: 'i-lucide-box',
    to: '/docs/components'
  },
  {
    label: 'Breadcrumb',
    icon: 'i-lucide-link',
    to: '/docs/components/breadcrumb'
  }
])
</script>

<template>
  <UBreadcrumb color="secondary" :items="items" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { BreadcrumbItem } from '@nuxt/ui'

const items = ref<BreadcrumbItem[]>([
  {
    label: 'Docs',
    icon: 'i-lucide-book-open',
    to: '/docs'
  },
  {
    label: 'Components',
    icon: 'i-lucide-box',
    to: '/docs/components'
  },
  {
    label: 'Breadcrumb',
    icon: 'i-lucide-link',
    to: '/docs/components/breadcrumb'
  }
])
</script>

<template>
  <UBreadcrumb color="secondary" :items="items" />
</template>

Examples

With separator slot

Use the #separator slot to customize the separator between each item.

<script setup lang="ts">
import type { BreadcrumbItem } from '@nuxt/ui'

const items: BreadcrumbItem[] = [
  {
    label: 'Docs',
    to: '/docs'
  },
  {
    label: 'Components',
    to: '/docs/components'
  },
  {
    label: 'Breadcrumb',
    to: '/docs/components/breadcrumb'
  }
]
</script>

<template>
  <UBreadcrumb :items="items">
    <template #separator>
      <span class="mx-2 text-muted">/</span>
    </template>
  </UBreadcrumb>
</template>

With custom slot

Use the slot property to customize a specific item.

You will have access to the following slots:

  • #{{ item.slot }}
  • #{{ item.slot }}-leading
  • #{{ item.slot }}-label
  • #{{ item.slot }}-trailing
<script setup lang="ts">
import type { BreadcrumbItem } from '@nuxt/ui'

const items = [
  {
    label: 'Home',
    to: '/'
  },
  {
    slot: 'dropdown' as const,
    icon: 'i-lucide-ellipsis',
    children: [
      {
        label: 'Documentation',
        to: '/docs'
      },
      {
        label: 'Themes'
      },
      {
        label: 'GitHub'
      }
    ]
  },
  {
    label: 'Components',
    to: '/docs/components'
  },
  {
    label: 'Breadcrumb',
    to: '/docs/components/breadcrumb'
  }
] satisfies BreadcrumbItem[]
</script>

<template>
  <UBreadcrumb :items="items">
    <template #dropdown="{ item }">
      <UDropdownMenu :items="item.children">
        <UButton :icon="item.icon" color="neutral" variant="link" class="p-0.5" />
      </UDropdownMenu>
    </template>
  </UBreadcrumb>
</template>
You can also use the #item, #item-leading, #item-label and #item-trailing slots to customize all items.

API

Props

Prop Default Type
as'nav'any

The element or component this component should render as.

items T[]
separatorIconappConfig.ui.icons.chevronRightany

The icon to use as a separator.

color'primary' "primary" | "secondary" | "success" | "info" | "warning" | "error" | "neutral"
labelKey'label' keyof Extract<NestedItem<T>, object> & string | DotPathKeys<Extract<NestedItem<T>, object>>

The key used to get the label from the item.

ui { root?: ClassNameValue; list?: ClassNameValue; item?: ClassNameValue; link?: ClassNameValue; linkLeadingIcon?: ClassNameValue; linkLeadingAvatar?: ClassNameValue; linkLeadingAvatarSize?: ClassNameValue; linkLabel?: ClassNameValue; separator?: ClassNameValue; separatorIcon?: ClassNameValue; }

Slots

Slot Type
item{ item: T; index: number; active: boolean; ui: object; }
item-leading{ item: T; index: number; active: boolean; ui: object; }
item-label{ item: T; index: number; active: boolean; }
item-trailing{ item: T; index: number; active: boolean; }
separator{ ui: object; }

Theme

app.config.ts
export default defineAppConfig({
  ui: {
    breadcrumb: {
      slots: {
        root: 'relative min-w-0',
        list: 'flex items-center gap-1.5',
        item: 'flex min-w-0',
        link: 'group relative flex items-center gap-1.5 text-sm min-w-0',
        linkLeadingIcon: 'shrink-0 size-5',
        linkLeadingAvatar: 'shrink-0',
        linkLeadingAvatarSize: '2xs',
        linkLabel: 'truncate',
        separator: 'flex',
        separatorIcon: 'shrink-0 size-5 text-muted'
      },
      variants: {
        active: {
          true: {
            link: 'font-semibold'
          },
          false: {
            link: 'text-muted font-medium'
          }
        },
        disabled: {
          true: {
            link: 'cursor-not-allowed opacity-75'
          }
        },
        to: {
          true: ''
        },
        color: {
          primary: {
            link: 'focus-visible:outline-primary'
          },
          secondary: {
            link: 'focus-visible:outline-secondary'
          },
          success: {
            link: 'focus-visible:outline-success'
          },
          info: {
            link: 'focus-visible:outline-info'
          },
          warning: {
            link: 'focus-visible:outline-warning'
          },
          error: {
            link: 'focus-visible:outline-error'
          },
          neutral: {
            link: 'focus-visible:outline-inverted'
          }
        }
      },
      compoundVariants: [
        {
          disabled: false,
          active: false,
          to: true,
          class: {
            link: [
              'hover:text-default',
              'transition-colors'
            ]
          }
        },
        {
          color: 'primary',
          active: true,
          class: {
            link: 'text-primary'
          }
        },
        {
          color: 'neutral',
          active: true,
          class: {
            link: 'text-highlighted'
          }
        }
      ],
      defaultVariants: {
        color: 'primary'
      }
    }
  }
})
vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import ui from '@nuxt/ui/vite'

export default defineConfig({
  plugins: [
    vue(),
    ui({
      ui: {
        breadcrumb: {
          slots: {
            root: 'relative min-w-0',
            list: 'flex items-center gap-1.5',
            item: 'flex min-w-0',
            link: 'group relative flex items-center gap-1.5 text-sm min-w-0',
            linkLeadingIcon: 'shrink-0 size-5',
            linkLeadingAvatar: 'shrink-0',
            linkLeadingAvatarSize: '2xs',
            linkLabel: 'truncate',
            separator: 'flex',
            separatorIcon: 'shrink-0 size-5 text-muted'
          },
          variants: {
            active: {
              true: {
                link: 'font-semibold'
              },
              false: {
                link: 'text-muted font-medium'
              }
            },
            disabled: {
              true: {
                link: 'cursor-not-allowed opacity-75'
              }
            },
            to: {
              true: ''
            },
            color: {
              primary: {
                link: 'focus-visible:outline-primary'
              },
              secondary: {
                link: 'focus-visible:outline-secondary'
              },
              success: {
                link: 'focus-visible:outline-success'
              },
              info: {
                link: 'focus-visible:outline-info'
              },
              warning: {
                link: 'focus-visible:outline-warning'
              },
              error: {
                link: 'focus-visible:outline-error'
              },
              neutral: {
                link: 'focus-visible:outline-inverted'
              }
            }
          },
          compoundVariants: [
            {
              disabled: false,
              active: false,
              to: true,
              class: {
                link: [
                  'hover:text-default',
                  'transition-colors'
                ]
              }
            },
            {
              color: 'primary',
              active: true,
              class: {
                link: 'text-primary'
              }
            },
            {
              color: 'neutral',
              active: true,
              class: {
                link: 'text-highlighted'
              }
            }
          ],
          defaultVariants: {
            color: 'primary'
          }
        }
      }
    })
  ]
})
Some colors in compoundVariants are omitted for readability. Check out the source code on GitHub.

Changelog

No recent changes