Fiber UI LogoFiberUI

Breadcrumb

Displays the path to the current resource using a hierarchy of links.

Basic Usage

"use client";

import {
    Breadcrumb,
    BreadcrumbList,
    BreadcrumbItem,
    BreadcrumbLink,
    BreadcrumbPage,
    BreadcrumbSeparator,
} from "@repo/ui/components/breadcrumb";

export const Example1 = () => {
    return (
        <Breadcrumb>
            <BreadcrumbList>
                <BreadcrumbItem>
                    <BreadcrumbLink href="#">Home</BreadcrumbLink>
                </BreadcrumbItem>
                <BreadcrumbSeparator />
                <BreadcrumbItem>
                    <BreadcrumbLink href="#">Products</BreadcrumbLink>
                </BreadcrumbItem>
                <BreadcrumbSeparator />
                <BreadcrumbItem>
                    <BreadcrumbLink href="#">Electronics</BreadcrumbLink>
                </BreadcrumbItem>
                <BreadcrumbSeparator />
                <BreadcrumbItem>
                    <BreadcrumbPage>Smartphones</BreadcrumbPage>
                </BreadcrumbItem>
            </BreadcrumbList>
        </Breadcrumb>
    );
};

Custom Separator

Slash separator

Text separator

"use client";

import {
    Breadcrumb,
    BreadcrumbList,
    BreadcrumbItem,
    BreadcrumbLink,
    BreadcrumbPage,
    BreadcrumbSeparator,
} from "@repo/ui/components/breadcrumb";
import { SlashIcon } from "lucide-react";

export const Example2 = () => {
    return (
        <div className="flex flex-col gap-6">
            <div>
                <p className="text-muted-foreground mb-2 text-sm">
                    Slash separator
                </p>
                <Breadcrumb>
                    <BreadcrumbList>
                        <BreadcrumbItem>
                            <BreadcrumbLink href="#">Home</BreadcrumbLink>
                        </BreadcrumbItem>
                        <BreadcrumbSeparator>
                            <SlashIcon />
                        </BreadcrumbSeparator>
                        <BreadcrumbItem>
                            <BreadcrumbLink href="#">Components</BreadcrumbLink>
                        </BreadcrumbItem>
                        <BreadcrumbSeparator>
                            <SlashIcon />
                        </BreadcrumbSeparator>
                        <BreadcrumbItem>
                            <BreadcrumbPage>Breadcrumb</BreadcrumbPage>
                        </BreadcrumbItem>
                    </BreadcrumbList>
                </Breadcrumb>
            </div>
            <div>
                <p className="text-muted-foreground mb-2 text-sm">
                    Text separator
                </p>
                <Breadcrumb>
                    <BreadcrumbList>
                        <BreadcrumbItem>
                            <BreadcrumbLink href="#">Home</BreadcrumbLink>
                        </BreadcrumbItem>
                        <BreadcrumbSeparator>
                            <span className="text-muted-foreground">›</span>
                        </BreadcrumbSeparator>
                        <BreadcrumbItem>
                            <BreadcrumbLink href="#">Components</BreadcrumbLink>
                        </BreadcrumbItem>
                        <BreadcrumbSeparator>
                            <span className="text-muted-foreground">›</span>
                        </BreadcrumbSeparator>
                        <BreadcrumbItem>
                            <BreadcrumbPage>Breadcrumb</BreadcrumbPage>
                        </BreadcrumbItem>
                    </BreadcrumbList>
                </Breadcrumb>
            </div>
        </div>
    );
};

Collapsed State

"use client";

import {
    Breadcrumb,
    BreadcrumbList,
    BreadcrumbItem,
    BreadcrumbLink,
    BreadcrumbPage,
    BreadcrumbSeparator,
    BreadcrumbEllipsis,
} from "@repo/ui/components/breadcrumb";

export const Example3 = () => {
    return (
        <Breadcrumb>
            <BreadcrumbList>
                <BreadcrumbItem>
                    <BreadcrumbLink href="#">Home</BreadcrumbLink>
                </BreadcrumbItem>
                <BreadcrumbSeparator />
                <BreadcrumbItem>
                    <BreadcrumbEllipsis />
                </BreadcrumbItem>
                <BreadcrumbSeparator />
                <BreadcrumbItem>
                    <BreadcrumbLink href="#">Category</BreadcrumbLink>
                </BreadcrumbItem>
                <BreadcrumbSeparator />
                <BreadcrumbItem>
                    <BreadcrumbLink href="#">Sub-Category</BreadcrumbLink>
                </BreadcrumbItem>
                <BreadcrumbSeparator />
                <BreadcrumbItem>
                    <BreadcrumbPage>Current Page</BreadcrumbPage>
                </BreadcrumbItem>
            </BreadcrumbList>
        </Breadcrumb>
    );
};

Simple Breadcrumb

Use SimpleBreadcrumb for auto-generation from an items array with optional auto-collapse.

Full breadcrumb

Collapsed (maxItems=4)

"use client";

import { SimpleBreadcrumb } from "@repo/ui/components/breadcrumb";

export const Example4 = () => {
    const items = [
        { label: "Home", href: "#" },
        { label: "Products", href: "#" },
        { label: "Electronics", href: "#" },
        { label: "Smartphones", href: "#" },
        { label: "iPhone 15 Pro" },
    ];

    return (
        <div className="flex flex-col gap-6">
            <div>
                <p className="text-muted-foreground mb-2 text-sm">
                    Full breadcrumb
                </p>
                <SimpleBreadcrumb items={items} />
            </div>
            <div>
                <p className="text-muted-foreground mb-2 text-sm">
                    Collapsed (maxItems=4)
                </p>
                <SimpleBreadcrumb items={items} maxItems={4} />
            </div>
        </div>
    );
};

With Icons

"use client";

import { SimpleBreadcrumb } from "@repo/ui/components/breadcrumb";
import { HomeIcon, FolderIcon, FileIcon } from "lucide-react";

export const Example5 = () => {
    const items = [
        {
            label: "Home",
            href: "#",
            icon: <HomeIcon className="mr-1.5 size-4" />,
        },
        {
            label: "Documents",
            href: "#",
            icon: <FolderIcon className="mr-1.5 size-4" />,
        },
        {
            label: "Projects",
            href: "#",
            icon: <FolderIcon className="mr-1.5 size-4" />,
        },
        {
            label: "report.pdf",
            icon: <FileIcon className="mr-1.5 size-4" />,
        },
    ];

    return <SimpleBreadcrumb items={items} />;
};

Component Code

"use client";

import { forwardRef, Fragment } from "react";
import { cn } from "@repo/ui/lib/utils";
import { Slot } from "@repo/ui/components/slot";
import { ChevronRightIcon, MoreHorizontalIcon } from "lucide-react";

interface BreadcrumbProps extends React.ComponentProps<"nav"> {
    /** Separator between items */
    separator?: React.ReactNode;
}

const Breadcrumb = forwardRef<HTMLElement, BreadcrumbProps>(
    ({ className, ...props }, ref) => {
        return (
            <nav
                ref={ref}
                aria-label="Breadcrumb"
                className={className}
                {...props}
            />
        );
    },
);
Breadcrumb.displayName = "Breadcrumb";

const BreadcrumbList = forwardRef<HTMLOListElement, React.ComponentProps<"ol">>(
    ({ className, ...props }, ref) => {
        return (
            <ol
                ref={ref}
                className={cn(
                    "text-muted-foreground wrap-break-word flex list-none flex-wrap items-center gap-1.5 text-sm sm:gap-2.5",
                    className,
                )}
                {...props}
            />
        );
    },
);
BreadcrumbList.displayName = "BreadcrumbList";

const BreadcrumbItem = forwardRef<HTMLLIElement, React.ComponentProps<"li">>(
    ({ className, ...props }, ref) => {
        return (
            <li
                ref={ref}
                className={cn("inline-flex items-center gap-1.5", className)}
                {...props}
            />
        );
    },
);
BreadcrumbItem.displayName = "BreadcrumbItem";

interface BreadcrumbLinkProps extends React.ComponentProps<"a"> {
    asChild?: boolean;
}

const BreadcrumbLink = forwardRef<HTMLAnchorElement, BreadcrumbLinkProps>(
    ({ asChild, className, children, ...props }, ref) => {
        const linkClassName = cn(
            "hover:text-foreground cursor-pointer transition-colors",
            className,
        );

        const Comp = asChild ? Slot : "a";
        return (
            <Comp ref={ref} className={linkClassName} {...props}>
                {children}
            </Comp>
        );
    },
);
BreadcrumbLink.displayName = "BreadcrumbLink";

const BreadcrumbPage = forwardRef<
    HTMLSpanElement,
    React.ComponentProps<"span">
>(({ className, ...props }, ref) => {
    return (
        <span
            ref={ref}
            role="link"
            aria-disabled="true"
            aria-current="page"
            className={cn("text-foreground font-medium", className)}
            {...props}
        />
    );
});
BreadcrumbPage.displayName = "BreadcrumbPage";

interface BreadcrumbSeparatorProps extends React.ComponentProps<"li"> {
    children?: React.ReactNode;
}

const BreadcrumbSeparator = forwardRef<HTMLLIElement, BreadcrumbSeparatorProps>(
    ({ children, className, ...props }, ref) => {
        return (
            <li
                ref={ref}
                role="presentation"
                aria-hidden="true"
                className={cn("[&>svg]:size-3.5", className)}
                {...props}
            >
                {children ?? <ChevronRightIcon />}
            </li>
        );
    },
);
BreadcrumbSeparator.displayName = "BreadcrumbSeparator";

interface BreadcrumbEllipsisProps extends React.ComponentProps<"span"> {
    onClick?: () => void;
}

const BreadcrumbEllipsis = forwardRef<HTMLSpanElement, BreadcrumbEllipsisProps>(
    ({ className, onClick, ...props }, ref) => {
        const isClickable = !!onClick;

        if (isClickable) {
            return (
                <button
                    type="button"
                    onClick={onClick}
                    className={cn(
                        "flex size-9 items-center justify-center rounded-md",
                        "hover:bg-accent hover:text-accent-foreground transition-colors",
                        "cursor-pointer",
                        className,
                    )}
                    aria-label="Show more breadcrumbs"
                >
                    <MoreHorizontalIcon className="size-4" />
                    <span className="sr-only">More</span>
                </button>
            );
        }

        return (
            <span
                ref={ref}
                role="presentation"
                aria-hidden="true"
                className={cn(
                    "flex size-9 items-center justify-center",
                    className,
                )}
                {...props}
            >
                <MoreHorizontalIcon className="size-4" />
                <span className="sr-only">More</span>
            </span>
        );
    },
);
BreadcrumbEllipsis.displayName = "BreadcrumbEllipsis";

export interface BreadcrumbItemData {
    label: string;
    href?: string;
    icon?: React.ReactNode;
}

interface SimpleBreadcrumbProps extends Omit<BreadcrumbProps, "children"> {
    items: BreadcrumbItemData[];
    separator?: React.ReactNode;
    maxItems?: number;
    itemsBeforeCollapse?: number;
    itemsAfterCollapse?: number;
    onExpandClick?: () => void;
}

const SimpleBreadcrumb = forwardRef<HTMLElement, SimpleBreadcrumbProps>(
    (
        {
            items,
            separator,
            maxItems,
            itemsBeforeCollapse = 1,
            itemsAfterCollapse = 2,
            onExpandClick,
            className,
            ...props
        },
        ref,
    ) => {
        const shouldCollapse = maxItems && items.length > maxItems;

        let displayItems = items;
        if (shouldCollapse) {
            const before = items.slice(0, itemsBeforeCollapse);
            const after = items.slice(-itemsAfterCollapse);
            displayItems = [
                ...before,
                { label: "...", href: undefined },
                ...after,
            ];
        }

        return (
            <Breadcrumb ref={ref} className={className} {...props}>
                <BreadcrumbList>
                    {displayItems.map((item, index) => {
                        const isLast = index === displayItems.length - 1;
                        const isEllipsis = item.label === "...";

                        return (
                            <Fragment key={`${item.label}-${index}`}>
                                <BreadcrumbItem>
                                    {isEllipsis ? (
                                        <BreadcrumbEllipsis
                                            onClick={onExpandClick}
                                        />
                                    ) : isLast ? (
                                        <BreadcrumbPage>
                                            {item.icon}
                                            {item.label}
                                        </BreadcrumbPage>
                                    ) : (
                                        <BreadcrumbLink href={item.href}>
                                            {item.icon}
                                            {item.label}
                                        </BreadcrumbLink>
                                    )}
                                </BreadcrumbItem>
                                {!isLast && (
                                    <BreadcrumbSeparator>
                                        {separator}
                                    </BreadcrumbSeparator>
                                )}
                            </Fragment>
                        );
                    })}
                </BreadcrumbList>
            </Breadcrumb>
        );
    },
);
SimpleBreadcrumb.displayName = "SimpleBreadcrumb";

export {
    Breadcrumb,
    BreadcrumbList,
    BreadcrumbItem,
    BreadcrumbLink,
    BreadcrumbPage,
    BreadcrumbSeparator,
    BreadcrumbEllipsis,
    SimpleBreadcrumb,
};