A compact path trail with a clear current location.
pnpm dlx shadcn@latest add @latheui/breadcrumbFirst time? Run npx latheui init once to add the @latheui registry. The CLI then writes the source into your project and installs what it needs. Or add it by hand:
Install the npm dependencies.
pnpm add lucide-react motionAdd the Lathe items this component imports.
lib/motion.tsCopy the source into your project.
"use client"
import * as React from "react"
import { ChevronRightIcon } from "lucide-react"
import { AnimatePresence, motion } from "motion/react"
import { cn } from "@/lib/utils"
import { fade, spring, useMotionSafe } from "@/lib/motion"
export type BreadcrumbItem = { label: string; href?: string }
export type BreadcrumbProps = React.ComponentProps<"nav"> & {
items: BreadcrumbItem[]
/** Called when a linked item is clicked. Call `event.preventDefault()` to handle the navigation yourself. */
onItemClick?: (
item: BreadcrumbItem,
index: number,
event: React.MouseEvent<HTMLAnchorElement>
) => void
}
export function Breadcrumb({
items,
onItemClick,
className,
...props
}: BreadcrumbProps) {
const { reduced, safe } = useMotionSafe()
// Levels that leave slide back toward the trail as they fade; new ones arrive the same way.
const away = { opacity: 0, x: reduced ? 0 : -8 }
return (
<nav
aria-label="Breadcrumb"
className={cn("text-sm", className)}
{...props}
>
<ol className="flex flex-wrap items-center gap-1.5">
<AnimatePresence initial={false}>
{items.map((item, i) => (
<motion.li
key={i}
initial={away}
animate={{ opacity: 1, x: 0 }}
exit={{ ...away, transition: fade }}
transition={safe(spring.snappy)}
className="flex min-w-0 items-center gap-1.5"
>
{i > 0 && (
<ChevronRightIcon
aria-hidden="true"
className="size-3.5 shrink-0 text-muted-foreground"
/>
)}
{i === items.length - 1 ? (
<span aria-current="page" className="font-medium">
{item.label}
</span>
) : item.href ? (
<a
href={item.href}
onClick={(event) => onItemClick?.(item, i, event)}
className="rounded-sm text-muted-foreground outline-none hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring"
>
{item.label}
</a>
) : (
<span className="text-muted-foreground">{item.label}</span>
)}
</motion.li>
))}
</AnimatePresence>
</ol>
</nav>
)
}Depends on
| Prop | Type | Default | Description |
|---|---|---|---|
| items* (required) | BreadcrumbItem[] | — | Ordered labels and optional hrefs. The last item is current. |
| onItemClick | (item, index, event) => void | — | Called when a linked item is clicked. Call event.preventDefault() to handle the navigation yourself. |
| aria-label | string | "Breadcrumb" | Navigation landmark name. |
Combine the control with your own layout. Semantic colors follow the active theme.
import { Breadcrumb } from "@/components/ui/breadcrumb"
export default function Demo(){return <Breadcrumb items={[{label:"Library",href:"/components"},{label:"Navigation",href:"/components"},{label:"Breadcrumb"}]}/>}