avertra-ui
uibreadcrumbsource: ok · hit
Breadcrumb
A breadcrumb navigation component.
npx shadcn add "https://micomponents.micustomer.io/r/breadcrumb.json"free
No selection tags yet — empty means no evidence, not lack of support.
Files1 · source cached 10/9/2026, 8:47:38 AM
src/components/ui/breadcrumb.tsx
"use client";
import * as React from "react";
import {
Breadcrumb,
BreadcrumbItem,
BreadcrumbLink,
BreadcrumbList,
BreadcrumbPage,
BreadcrumbSeparator,
} from "../../app/primitives/breadcrumb";
import { CaretRight } from "phosphor-react";
interface BreadcrumbProps {
path: string;
homeElement?: React.ReactNode;
containerClasses?: string;
listClasses?: string;
activeItemClasses?: string;
language?: string;
icons?: {
[segment: string]: React.ReactNode;
};
spliteStyle?: "default" | "arrow";
}
export const DynamicBreadcrumb: React.FC<BreadcrumbProps> = ({
path,
homeElement,
containerClasses,
listClasses,
activeItemClasses,
language = "en",
icons = {},
spliteStyle = "default",
}) => {
const pathNames = path
.split("/")
.filter((segment) => segment !== "dashboard" && segment.length > 0);
console.log({ path, pathNames });
const getHref = (index: number, paths: string[]) =>
`/${language}/${paths
.slice(0, index + 1)
.join(
spliteStyle === "default" ? "/" : spliteStyle === "arrow" ? ">" : "/",
)}`;
let displayPaths: {
name: string;
href: string;
isLast: boolean;
isEllipsis?: boolean;
}[] = [];
const total = pathNames.length;
if (total <= 3) {
displayPaths = pathNames.map((name, index) => ({
name,
href: getHref(index, pathNames),
isLast: index === total - 1,
}));
} else {
displayPaths = [
{ name: pathNames[0], href: getHref(0, pathNames), isLast: false },
{ name: "...", href: "", isLast: false, isEllipsis: true },
{
name: pathNames[total - 2],
href: getHref(total - 2, pathNames),
isLast: false,
},
{
name: pathNames[total - 1],
href: getHref(total - 1, pathNames),
isLast: true,
},
];
}
const defaultHomeElement = (
<BreadcrumbLink
className="text-secondary-foreground"
href={`/${language}`}
aria-label="Dashboard"
>
<span className="flex items-center gap-1">
{icons?.["dashboard"] && (
<span className="shrink-0">{icons["dashboard"]}</span>
)}
Dashboard
</span>
</BreadcrumbLink>
);
return (
<Breadcrumb className={containerClasses}>
<BreadcrumbList className={listClasses}>
<BreadcrumbItem>{homeElement ?? defaultHomeElement}</BreadcrumbItem>
{displayPaths.length > 0 && (
<BreadcrumbSeparator>
{spliteStyle === "arrow" ? (
<CaretRight size={16} className="text-muted-foreground" />
) : (
spliteStyle === "default" && (
<span className="text-muted-foreground">/</span>
)
)}
</BreadcrumbSeparator>
)}
{displayPaths.map((segment, index) => (
<React.Fragment key={index}>
<BreadcrumbItem className="capitalize">
{segment.isEllipsis ? (
<BreadcrumbPage className="text-muted-foreground">
...
</BreadcrumbPage>
) : segment.isLast ? (
<BreadcrumbPage className={activeItemClasses}>
<span className="flex items-center gap-1">
{icons?.[segment.name] && (
<span className="shrink-0">{icons[segment.name]}</span>
)}
{segment.name.replace(/-/g, " ")}
</span>
</BreadcrumbPage>
) : (
<BreadcrumbLink
href={segment.href}
className="text-muted-foreground"
>
<span className="flex items-center gap-1">
{icons?.[segment.name] && (
<span className="shrink-0">{icons[segment.name]}</span>
)}
{segment.name.replace(/-/g, " ")}
</span>
</BreadcrumbLink>
)}
</BreadcrumbItem>
{index < displayPaths.length - 1 && (
<BreadcrumbSeparator>
{spliteStyle === "arrow" ? (
<CaretRight size={16} className="text-muted-foreground" />
) : (
spliteStyle === "default" && (
<span className="text-muted-foreground">/</span>
)
)}
</BreadcrumbSeparator>
)}
</React.Fragment>
))}
</BreadcrumbList>
</Breadcrumb>
);
};