Skip to content
edmi-ui

Breadcrumb

Shows where a page sits in the hierarchy. The last item is the current page and is not a link.

StackBlitz ↗StackBlitz ↗StackBlitz ↗
Terminal window
npx shadcn@latest add @edmi-ui/breadcrumb
Terminal window
pnpm dlx shadcn@latest add @edmi-ui/breadcrumb
Terminal window
yarn dlx shadcn@latest add @edmi-ui/breadcrumb
Terminal window
bunx shadcn@latest add @edmi-ui/breadcrumb

Pick your package manager above; the choice is remembered. Add the @edmi-ui registry first, see Getting started.

Terminal window
npx shadcn-vue@latest add @edmi-ui/breadcrumb
Terminal window
pnpm dlx shadcn-vue@latest add @edmi-ui/breadcrumb
Terminal window
yarn dlx shadcn-vue@latest add @edmi-ui/breadcrumb
Terminal window
bunx shadcn-vue@latest add @edmi-ui/breadcrumb

Pick your package manager above; the choice is remembered. Add the @edmi-ui registry first, see Getting started.

Terminal window
npx shadcn-svelte@latest add https://viandwi24.github.io/edmi-ui/r/svelte/breadcrumb.json
Terminal window
pnpm dlx shadcn-svelte@latest add https://viandwi24.github.io/edmi-ui/r/svelte/breadcrumb.json
Terminal window
yarn dlx shadcn-svelte@latest add https://viandwi24.github.io/edmi-ui/r/svelte/breadcrumb.json
Terminal window
bunx --bun shadcn-svelte@latest add https://viandwi24.github.io/edmi-ui/r/svelte/breadcrumb.json

Pick your package manager above; the choice is remembered. Add the @edmi-ui registry first, see Getting started.

import {
Breadcrumb,
BreadcrumbEllipsis,
BreadcrumbItem,
BreadcrumbLink,
BreadcrumbList,
BreadcrumbPage,
BreadcrumbSeparator,
} from "@/components/ui/breadcrumb";
<Breadcrumb>
<BreadcrumbList>
<BreadcrumbItem>
<BreadcrumbLink href="#home">Home</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbEllipsis />
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbLink href="#explore">Explore</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbPage>MAG4</BreadcrumbPage>
</BreadcrumbItem>
</BreadcrumbList>
</Breadcrumb>
<script setup lang="ts">
import {
Breadcrumb,
BreadcrumbEllipsis,
BreadcrumbItem,
BreadcrumbLink,
BreadcrumbList,
BreadcrumbPage,
BreadcrumbSeparator,
} from "@/components/ui/breadcrumb";
</script>
<template>
<Breadcrumb>
<BreadcrumbList>
<BreadcrumbItem>
<BreadcrumbLink href="#home">Home</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbEllipsis />
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbLink href="#explore">Explore</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbPage>MAG4</BreadcrumbPage>
</BreadcrumbItem>
</BreadcrumbList>
</Breadcrumb>
</template>
<script lang="ts">
import * as Breadcrumb from "$lib/components/ui/breadcrumb";
</script>
<Breadcrumb.Root>
<Breadcrumb.List>
<Breadcrumb.Item>
<Breadcrumb.Link href="#home">Home</Breadcrumb.Link>
</Breadcrumb.Item>
<Breadcrumb.Separator />
<Breadcrumb.Item>
<Breadcrumb.Ellipsis />
</Breadcrumb.Item>
<Breadcrumb.Separator />
<Breadcrumb.Item>
<Breadcrumb.Link href="#explore">Explore</Breadcrumb.Link>
</Breadcrumb.Item>
<Breadcrumb.Separator />
<Breadcrumb.Item>
<Breadcrumb.Page>MAG4</Breadcrumb.Page>
</Breadcrumb.Item>
</Breadcrumb.List>
</Breadcrumb.Root>
registry/ui/breadcrumb.tsx
import { mergeProps } from "@base-ui/react/merge-props";
import { useRender } from "@base-ui/react/use-render";
import { cn } from "cn";
import type * as React from "react";
import { CaretRightIcon, DotsThreeIcon } from "@phosphor-icons/react";
function Breadcrumb({ className, ...props }: React.ComponentProps<"nav">) {
return (
<nav
aria-label="breadcrumb"
data-slot="breadcrumb"
className={cn(className)}
{...props}
/>
);
}
function BreadcrumbList({ className, ...props }: React.ComponentProps<"ol">) {
return (
<ol
data-slot="breadcrumb-list"
className={cn(
"flex flex-wrap items-center gap-1.5 text-sm wrap-break-word text-muted-foreground",
className,
)}
{...props}
/>
);
}
function BreadcrumbItem({ className, ...props }: React.ComponentProps<"li">) {
return (
<li
data-slot="breadcrumb-item"
className={cn("inline-flex items-center gap-1", className)}
{...props}
/>
);
}
function BreadcrumbLink({
className,
render,
...props
}: useRender.ComponentProps<"a">) {
return useRender({
defaultTagName: "a",
props: mergeProps<"a">(
{
className: cn("transition-colors hover:text-foreground", className),
},
props,
),
render,
state: {
slot: "breadcrumb-link",
},
});
}
function BreadcrumbPage({ className, ...props }: React.ComponentProps<"span">) {
return (
// biome-ignore lint/a11y/useFocusableInteractive: stock markup, current page is a disabled link
// biome-ignore lint/a11y/useSemanticElements: stock markup
<span
data-slot="breadcrumb-page"
role="link"
aria-disabled="true"
aria-current="page"
className={cn("font-normal text-foreground", className)}
{...props}
/>
);
}
function BreadcrumbSeparator({
children,
className,
...props
}: React.ComponentProps<"li">) {
return (
<li
data-slot="breadcrumb-separator"
role="presentation"
aria-hidden="true"
className={cn("[&>svg]:size-3.5", className)}
{...props}
>
{children ?? (
<CaretRightIcon
className="rtl:rotate-180"
/>
)}
</li>
);
}
function BreadcrumbEllipsis({
className,
...props
}: React.ComponentProps<"span">) {
return (
<span
data-slot="breadcrumb-ellipsis"
role="presentation"
aria-hidden="true"
className={cn(
"flex size-5 items-center justify-center [&>svg]:size-4",
className,
)}
{...props}
>
<DotsThreeIcon
/>
<span className="sr-only">More</span>
</span>
);
}
export {
Breadcrumb,
BreadcrumbEllipsis,
BreadcrumbItem,
BreadcrumbLink,
BreadcrumbList,
BreadcrumbPage,
BreadcrumbSeparator,
};
registry/ui/breadcrumb/Breadcrumb.vue
<script lang="ts" setup>
import type { HTMLAttributes } from "vue"
const props = defineProps<{
class?: HTMLAttributes["class"]
}>()
</script>
<template>
<nav
aria-label="breadcrumb"
data-slot="breadcrumb"
:class="props.class"
>
<slot />
</nav>
</template>
registry/ui/breadcrumb/BreadcrumbEllipsis.vue
<script lang="ts" setup>
import type { HTMLAttributes } from "vue"
import { MoreHorizontal } from "@lucide/vue"
import { cn } from "@/registry/edmi/lib/utils"
const props = defineProps<{
class?: HTMLAttributes["class"]
}>()
</script>
<template>
<span
data-slot="breadcrumb-ellipsis"
role="presentation"
aria-hidden="true"
:class="cn('flex size-5 items-center justify-center [&>svg]:size-4', props.class)"
>
<slot>
<MoreHorizontal />
</slot>
<span class="sr-only">More</span>
</span>
</template>
registry/ui/breadcrumb/BreadcrumbItem.vue
<script lang="ts" setup>
import type { HTMLAttributes } from "vue"
import { cn } from "@/registry/edmi/lib/utils"
const props = defineProps<{
class?: HTMLAttributes["class"]
}>()
</script>
<template>
<li
data-slot="breadcrumb-item"
:class="cn('inline-flex items-center gap-1', props.class)"
>
<slot />
</li>
</template>
registry/ui/breadcrumb/BreadcrumbLink.vue
<script lang="ts" setup>
import type { PrimitiveProps } from "reka-ui"
import type { HTMLAttributes } from "vue"
import { Primitive } from "reka-ui"
import { cn } from "@/registry/edmi/lib/utils"
const props = withDefaults(defineProps<PrimitiveProps & { class?: HTMLAttributes["class"] }>(), {
as: "a",
})
</script>
<template>
<Primitive
data-slot="breadcrumb-link"
:as="as"
:as-child="asChild"
:class="cn('transition-colors hover:text-foreground', props.class)"
>
<slot />
</Primitive>
</template>
registry/ui/breadcrumb/BreadcrumbList.vue
<script lang="ts" setup>
import type { HTMLAttributes } from "vue"
import { cn } from "@/registry/edmi/lib/utils"
const props = defineProps<{
class?: HTMLAttributes["class"]
}>()
</script>
<template>
<ol
data-slot="breadcrumb-list"
:class="cn('flex flex-wrap items-center gap-1.5 text-sm wrap-break-word text-muted-foreground', props.class)"
>
<slot />
</ol>
</template>
registry/ui/breadcrumb/BreadcrumbPage.vue
<script lang="ts" setup>
import type { HTMLAttributes } from "vue"
import { cn } from "@/registry/edmi/lib/utils"
const props = defineProps<{
class?: HTMLAttributes["class"]
}>()
</script>
<template>
<span
data-slot="breadcrumb-page"
role="link"
aria-disabled="true"
aria-current="page"
:class="cn('font-normal text-foreground', props.class)"
>
<slot />
</span>
</template>
registry/ui/breadcrumb/BreadcrumbSeparator.vue
<script lang="ts" setup>
import type { HTMLAttributes } from "vue"
import { ChevronRight } from "@lucide/vue"
import { cn } from "@/registry/edmi/lib/utils"
const props = defineProps<{
class?: HTMLAttributes["class"]
}>()
</script>
<template>
<li
data-slot="breadcrumb-separator"
role="presentation"
aria-hidden="true"
:class="cn('[&>svg]:size-3.5', props.class)"
>
<slot>
<ChevronRight class="rtl:rotate-180" />
</slot>
</li>
</template>
registry/ui/breadcrumb/index.ts
export { default as Breadcrumb } from "./Breadcrumb.vue";
export { default as BreadcrumbEllipsis } from "./BreadcrumbEllipsis.vue";
export { default as BreadcrumbItem } from "./BreadcrumbItem.vue";
export { default as BreadcrumbLink } from "./BreadcrumbLink.vue";
export { default as BreadcrumbList } from "./BreadcrumbList.vue";
export { default as BreadcrumbPage } from "./BreadcrumbPage.vue";
export { default as BreadcrumbSeparator } from "./BreadcrumbSeparator.vue";
src/lib/registry/ui/breadcrumb/breadcrumb-ellipsis.svelte
<script lang="ts">
import DotsThreeIcon from "phosphor-svelte/lib/DotsThree";
import { cn, type WithElementRef, type WithoutChildren } from "$lib/utils.js";
import type { HTMLAttributes } from "svelte/elements";
let {
ref = $bindable(null),
class: className,
...restProps
}: WithoutChildren<WithElementRef<HTMLAttributes<HTMLSpanElement>>> = $props();
</script>
<span
bind:this={ref}
data-slot="breadcrumb-ellipsis"
role="presentation"
aria-hidden="true"
class={cn(
"flex size-5 items-center justify-center [&>svg]:size-4", className)}
{...restProps}
>
<DotsThreeIcon
/>
<span class="sr-only">More</span>
</span>
src/lib/registry/ui/breadcrumb/breadcrumb-item.svelte
<script lang="ts">
import { cn, type WithElementRef } from "$lib/utils.js";
import type { HTMLLiAttributes } from "svelte/elements";
let {
ref = $bindable(null),
class: className,
children,
...restProps
}: WithElementRef<HTMLLiAttributes> = $props();
</script>
<li
bind:this={ref}
data-slot="breadcrumb-item"
class={cn(
"inline-flex items-center gap-1", className)}
{...restProps}
>
{@render children?.()}
</li>
src/lib/registry/ui/breadcrumb/breadcrumb-link.svelte
<script lang="ts">
import { cn, type WithElementRef } from "$lib/utils.js";
import type { Snippet } from "svelte";
import type { HTMLAnchorAttributes } from "svelte/elements";
let {
ref = $bindable(null),
class: className,
href = undefined,
child,
children,
...restProps
}: WithElementRef<HTMLAnchorAttributes> & {
child?: Snippet<[{ props: HTMLAnchorAttributes }]>;
} = $props();
const attrs = $derived({
"data-slot": "breadcrumb-link",
class: cn("transition-colors hover:text-foreground", className),
href,
...restProps,
});
</script>
{#if child}
{@render child({ props: attrs })}
{:else}
<a bind:this={ref} {...attrs}>
{@render children?.()}
</a>
{/if}
src/lib/registry/ui/breadcrumb/breadcrumb-list.svelte
<script lang="ts">
import { cn, type WithElementRef } from "$lib/utils.js";
import type { HTMLOlAttributes } from "svelte/elements";
let {
ref = $bindable(null),
class: className,
children,
...restProps
}: WithElementRef<HTMLOlAttributes> = $props();
</script>
<ol
bind:this={ref}
data-slot="breadcrumb-list"
class={cn(
"flex flex-wrap items-center gap-1.5 text-sm wrap-break-word text-muted-foreground", className)}
{...restProps}
>
{@render children?.()}
</ol>
src/lib/registry/ui/breadcrumb/breadcrumb-page.svelte
<script lang="ts">
import { cn, type WithElementRef } from "$lib/utils.js";
import type { HTMLAttributes } from "svelte/elements";
let {
ref = $bindable(null),
class: className,
children,
...restProps
}: WithElementRef<HTMLAttributes<HTMLSpanElement>> = $props();
</script>
<span
bind:this={ref}
data-slot="breadcrumb-page"
role="link"
aria-disabled="true"
aria-current="page"
class={cn(
"font-normal text-foreground", className)}
{...restProps}
>
{@render children?.()}
</span>
src/lib/registry/ui/breadcrumb/breadcrumb-separator.svelte
<script lang="ts">
import CaretRightIcon from "phosphor-svelte/lib/CaretRight";
import { cn, type WithElementRef } from "$lib/utils.js";
import type { HTMLLiAttributes } from "svelte/elements";
let {
ref = $bindable(null),
class: className,
children,
...restProps
}: WithElementRef<HTMLLiAttributes> = $props();
</script>
<li
bind:this={ref}
data-slot="breadcrumb-separator"
role="presentation"
aria-hidden="true"
class={cn("[&>svg]:size-3.5", className)}
{...restProps}
>
{#if children}
{@render children?.()}
{:else}
<CaretRightIcon
class="rtl:rotate-180"
/>
{/if}
</li>
src/lib/registry/ui/breadcrumb/breadcrumb.svelte
<script lang="ts">
import type { WithElementRef } from "$lib/utils.js";
import { cn } from "$lib/utils.js";
import type { HTMLAttributes } from "svelte/elements";
let {
ref = $bindable(null),
class: className,
children,
...restProps
}: WithElementRef<HTMLAttributes<HTMLElement>> = $props();
</script>
<nav
bind:this={ref}
data-slot="breadcrumb"
aria-label="breadcrumb"
class={cn(className)}
{...restProps}
>
{@render children?.()}
</nav>
src/lib/registry/ui/breadcrumb/index.ts
import Root from "./breadcrumb.svelte";
import Ellipsis from "./breadcrumb-ellipsis.svelte";
import Item from "./breadcrumb-item.svelte";
import Link from "./breadcrumb-link.svelte";
import List from "./breadcrumb-list.svelte";
import Page from "./breadcrumb-page.svelte";
import Separator from "./breadcrumb-separator.svelte";
export {
Ellipsis,
Ellipsis as BreadcrumbEllipsis,
Item,
Item as BreadcrumbItem,
Link,
Link as BreadcrumbLink,
List,
List as BreadcrumbList,
Page,
Page as BreadcrumbPage,
Root,
//
Root as Breadcrumb,
Separator,
Separator as BreadcrumbSeparator,
};
Prop Type Default
BreadcrumbLink render ReactElement <a> (Base UI, replaces asChild)
BreadcrumbSeparator children ReactNode chevron icon

Parts: Breadcrumb, BreadcrumbList, BreadcrumbItem, BreadcrumbLink, BreadcrumbPage, BreadcrumbSeparator, BreadcrumbEllipsis.

  • Muted links that darken to --foreground on hover; the current page uses --foreground.