Breadcrumb

Shows where the current page sits in the hierarchy.

<script setup lang="ts">
  import { Breadcrumb, BreadcrumbItem, BreadcrumbSeparator } from '@hina-ui/vue'
</script>

<template>
  <Breadcrumb>
    <BreadcrumbItem href="#">Home</BreadcrumbItem>
    <BreadcrumbSeparator />
    <BreadcrumbItem href="#">Galgame</BreadcrumbItem>
    <BreadcrumbSeparator />
    <BreadcrumbItem href="#">枕</BreadcrumbItem>
    <BreadcrumbSeparator />
    <BreadcrumbItem current>サクラノ詩</BreadcrumbItem>
  </Breadcrumb>
</template>
vue

Usage

import { Breadcrumb, BreadcrumbItem, BreadcrumbSeparator } from '@hina-ui/vue'
ts

Breadcrumb is the navigation landmark, BreadcrumbItem is one level of the hierarchy and BreadcrumbSeparator sits between items. Items and separators alternate, and the last item is marked with current.

A current item is not a link: it renders as text carrying aria-current="page". Linking the current page to itself achieves nothing and leaves screen readers announcing a link that goes nowhere.

<script setup lang="ts">
  import { Breadcrumb, BreadcrumbItem, BreadcrumbSeparator } from '@hina-ui/vue'
</script>

<template>
  <Breadcrumb>
    <BreadcrumbItem href="#">Home</BreadcrumbItem>
    <BreadcrumbSeparator />
    <BreadcrumbItem href="#">Light novels</BreadcrumbItem>
    <BreadcrumbSeparator />
    <BreadcrumbItem current>Spring and Asura</BreadcrumbItem>
  </Breadcrumb>
</template>
vue

A breadcrumb records position in the hierarchy, not browsing history. It runs from the site root down to the current page regardless of how the reader arrived.

Examples

Separator

The separator is a right-pointing chevron by default. The default slot replaces it with anything — a slash and a middle dot are the usual alternatives. Keep one separator style throughout a single trail.

Default

Slash

Text

<script setup lang="ts">
  import { Slash } from '@lucide/vue'
  import { Breadcrumb, BreadcrumbItem, BreadcrumbSeparator, Stack, Text } from '@hina-ui/vue'
</script>

<template>
  <Stack gap="md">
    <Stack gap="xs">
      <Text size="sm" tone="faint">Default</Text>
      <Breadcrumb>
        <BreadcrumbItem href="#">Home</BreadcrumbItem>
        <BreadcrumbSeparator />
        <BreadcrumbItem href="#">Manga</BreadcrumbItem>
        <BreadcrumbSeparator />
        <BreadcrumbItem current>Episode 12</BreadcrumbItem>
      </Breadcrumb>
    </Stack>

    <Stack gap="xs">
      <Text size="sm" tone="faint">Slash</Text>
      <Breadcrumb>
        <BreadcrumbItem href="#">Home</BreadcrumbItem>
        <BreadcrumbSeparator><Slash class="size-3.5" /></BreadcrumbSeparator>
        <BreadcrumbItem href="#">Manga</BreadcrumbItem>
        <BreadcrumbSeparator><Slash class="size-3.5" /></BreadcrumbSeparator>
        <BreadcrumbItem current>Episode 12</BreadcrumbItem>
      </Breadcrumb>
    </Stack>

    <Stack gap="xs">
      <Text size="sm" tone="faint">Text</Text>
      <Breadcrumb>
        <BreadcrumbItem href="#">Home</BreadcrumbItem>
        <BreadcrumbSeparator>·</BreadcrumbSeparator>
        <BreadcrumbItem href="#">Manga</BreadcrumbItem>
        <BreadcrumbSeparator>·</BreadcrumbSeparator>
        <BreadcrumbItem current>Episode 12</BreadcrumbItem>
      </Breadcrumb>
    </Stack>
  </Stack>
</template>
vue

Router links

as sets what an item renders as, defaulting to a. Pass a router component in Nuxt or Vue Router for client-side navigation; remaining attributes such as to and href pass through to that element.

Use as-child to take over rendering entirely, in which case the item’s classes are merged onto the slot’s root element.

<script setup lang="ts">
  import { NuxtLink } from '#components'
  import { Breadcrumb, BreadcrumbItem, BreadcrumbSeparator } from '@hina-ui/vue'

  const localePath = useLocalePath()
</script>

<template>
  <Breadcrumb>
    <BreadcrumbItem :as="NuxtLink" :to="localePath('/components/button')">Button</BreadcrumbItem>
    <BreadcrumbSeparator />
    <BreadcrumbItem :as="NuxtLink" :to="localePath('/components/tag')">Tag</BreadcrumbItem>
    <BreadcrumbSeparator />
    <BreadcrumbItem current>Breadcrumb</BreadcrumbItem>
  </Breadcrumb>
</template>
vue

Icons

An item can hold any content. The first item often uses an icon in place of the word “Home”; when it does, mark the icon aria-hidden and add a VisuallyHidden name for screen readers — otherwise the item is a link with no accessible name.

<script setup lang="ts">
  import { House } from '@lucide/vue'
  import { Breadcrumb, BreadcrumbItem, BreadcrumbSeparator, VisuallyHidden } from '@hina-ui/vue'
</script>

<template>
  <Breadcrumb>
    <BreadcrumbItem href="#" class="inline-flex items-center">
      <House class="size-4" aria-hidden="true" />
      <VisuallyHidden>Home</VisuallyHidden>
    </BreadcrumbItem>
    <BreadcrumbSeparator />
    <BreadcrumbItem href="#">Galgame</BreadcrumbItem>
    <BreadcrumbSeparator />
    <BreadcrumbItem current>ATRI -My Dear Moments-</BreadcrumbItem>
  </Breadcrumb>
</template>
vue

Landmark name

Breadcrumb renders as a nav landmark with an accessible name in the interface language. When a page holds several navigation landmarks, name each with label so they can be told apart in a screen reader’s landmark list.

<script setup lang="ts">
  import { Breadcrumb, BreadcrumbItem, BreadcrumbSeparator } from '@hina-ui/vue'
</script>

<template>
  <Breadcrumb label="Title location">
    <BreadcrumbItem href="#">Home</BreadcrumbItem>
    <BreadcrumbSeparator />
    <BreadcrumbItem href="#">Light novels</BreadcrumbItem>
    <BreadcrumbSeparator />
    <BreadcrumbItem current>Volume 3</BreadcrumbItem>
  </Breadcrumb>
</template>
vue

Accessibility

  • The wrapper is a nav landmark holding an ordered list, so screen readers announce the number of items and each item’s position.
  • Separators carry aria-hidden and are not announced.
  • The current item carries aria-current="page" and is not clickable.
  • The default landmark name follows the interface language (“Breadcrumb” in English) and label overrides it.
  • When an icon replaces text, supply a readable name separately.

API

Breadcrumb

Prop
Type
Default
Description
label
string
Interface language
Accessible name of the landmark
class
string
—
Classes appended to the root
Slot
Description
default
Alternating items and separators

BreadcrumbItem

Prop
Type
Default
Description
current
boolean
false
Whether this is the current page, rendered as text
as
string | Component
'a'
Element or component to render as
asChild
boolean
false
Let the slot’s root element do the rendering
class
string
—
Classes appended to the root

Remaining attributes pass through to the rendered element, such as href or a router component’s to.

Slot
Description
default
Item content

BreadcrumbSeparator

Prop
Type
Default
Description
class
string
—
Classes appended to the root
Slot
Description
default
Separator content, a right chevron by default