Breadcrumbs
A row of links that shows where the current page sits in a hierarchy, and lets the user go back to a parent page.
<Breadcrumbs :items="[
{ label: 'Workspace' },
{ label: 'Projects' },
{ label: 'Frappe UI' },
]" />Examples
Page header
Breadcrumbs on the left of a page header, with page actions on the right. The last item is the current page. The items here navigate with onClick.
<script setup lang="ts">
import { ref } from 'vue'
import { Breadcrumbs, Button } from 'frappe-ui'
const lastClicked = ref('')
const items = [
{ label: 'Projects', onClick: () => (lastClicked.value = 'Projects') },
{
label: 'Website redesign',
onClick: () => (lastClicked.value = 'Website redesign'),
},
{ label: 'Homepage copy' },
]
</script>
<template>
<div class="w-full max-w-2xl">
<header
class="flex h-12 items-center justify-between gap-4 border-b border-outline-gray-1 px-4"
>
<Breadcrumbs :items="items" />
<div class="flex shrink-0 items-center gap-2">
<Button icon-left="lucide-share-2">Share</Button>
<Button variant="solid" icon-left="lucide-plus">New task</Button>
</div>
</header>
<p class="px-4 pt-3 text-p-sm text-ink-gray-5">
{{ lastClicked ? `Opened ${lastClicked}` : 'Click a parent page' }}
</p>
</div>
</template>Path to a person
The #prefix slot shows an icon or an avatar before each label. The slot reads icon and user, which are extra fields on the items.
<script setup lang="ts">
import { Avatar, Breadcrumbs } from 'frappe-ui'
const email = '[email protected]'
const items = [
{ label: 'Teams', icon: 'lucide-users', onClick: () => {} },
{ label: 'Design', icon: 'lucide-palette', onClick: () => {} },
{
label: 'Jane Cooper',
user: { image: `https://i.pravatar.cc/80?u=${email}` },
},
]
</script>
<template>
<Breadcrumbs :items="items">
<template #prefix="{ item }">
<Avatar
v-if="item.user"
:image="item.user.image"
:label="item.label"
size="sm"
class="mr-1.5"
/>
<span
v-else
:class="item.icon"
class="mr-1.5 size-4 shrink-0"
aria-hidden="true"
/>
</template>
</Breadcrumbs>
</template>Behavior
Item shape
Each item needs a label. How the item navigates depends on the other fields:
routerenders a<router-link>.hrefrenders an<a>.- Neither renders a
<button>, so useonClickto navigate.
The last item is the current page. Its label truncates when space runs out, and the full label shows on hover.
Links that navigate in the app
Set href and onClick together when the app navigates by itself but the crumb must still be a real link. A plain left click runs onClick only. A click with Cmd, Ctrl or Shift, and a middle click, stay with the browser and open the URL. The context menu keeps "Copy link address".
const items = [
{
label: 'Dashboards',
href: '/app/dashboard',
onClick: () => router.push('/dashboard'),
},
{ label: 'Sales' },
]Extra fields
An item also carries any extra field you put on it. BreadcrumbItem has an open index signature, so a crumb can hold the record it came from and the #prefix and #suffix slots can read it back:
<Breadcrumbs :items="items">
<template #prefix="{ item }">
<Avatar v-if="item.user" :image="item.user.avatar" size="sm" />
</template>
</Breadcrumbs>#prefix renders before the crumb's label and #suffix after it. Each receives { item }, and they render for every crumb.
Long paths
When the items do not fit their container and there are more than two, all items except the last two move into a menu behind a "…" button. The menu opens each item with its onClick or route. An item with only href does nothing in that menu, so give it an onClick too.
Accessibility
- Breadcrumbs does not add a landmark. Wrap it in
<nav aria-label="Breadcrumb">when it is the page's main breadcrumb trail. - The
/separators are hidden from screen readers.
API Reference
Show types
import type { RouteDestination } from '../shared/route'
export interface BreadcrumbItem {
/** Text shown for the breadcrumb item */
label: string
/** Route location used when the item is a link */
route?: RouteDestination
/** URL used when the item is a plain link, ignored if `route` is set */
href?: string
/**
* Click handler for non-router breadcrumb items. Set it together with `href`
* to keep a real URL on the crumb and still navigate in-app: a plain left
* click runs the handler only, a modified click opens the URL as usual.
*/
onClick?: (event?: MouseEvent) => void
/** Allows passing additional custom fields */
[key: string]: any
}
export interface BreadcrumbsProps {
/** Ordered list of breadcrumb items */
items: BreadcrumbItem[]
}Ordered list of breadcrumb items
| Slot | Payload |
|---|---|
prefix | { item: BreadcrumbItem; } Content shown before each breadcrumb label |
suffix | { item: BreadcrumbItem; } Content shown after each breadcrumb label |
Content shown before each breadcrumb label
Content shown after each breadcrumb label