Skip to content

Commit 4538d4e

Browse files
feat: added breadcrumb component
1 parent 74e0d8b commit 4538d4e

File tree

11 files changed

+346
-0
lines changed

11 files changed

+346
-0
lines changed

components/retroui/Breadcrumb.tsx

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
import * as React from "react"
2+
import { Slot } from "@radix-ui/react-slot"
3+
import { ChevronRight, MoreHorizontal } from "lucide-react"
4+
import { cn } from "@/lib/utils"
5+
6+
const BreadcrumbRoot = React.forwardRef<
7+
HTMLElement,
8+
React.ComponentPropsWithoutRef<"nav"> & {
9+
separator?: React.ReactNode
10+
}
11+
>(({ className, ...props }, ref) => (
12+
<nav
13+
ref={ref}
14+
aria-label="breadcrumb"
15+
className={cn("w-full text-sm", className)}
16+
{...props}
17+
/>
18+
))
19+
BreadcrumbRoot.displayName = "Breadcrumb"
20+
21+
const BreadcrumbList = React.forwardRef<
22+
HTMLOListElement,
23+
React.ComponentPropsWithoutRef<"ol">
24+
>(({ className, ...props }, ref) => (
25+
<ol
26+
ref={ref}
27+
className={cn(
28+
"flex flex-wrap items-center gap-1.5 sm:gap-2.5 text-muted-foreground",
29+
className
30+
)}
31+
{...props}
32+
/>
33+
))
34+
BreadcrumbList.displayName = "BreadcrumbList"
35+
36+
const BreadcrumbItem = React.forwardRef<
37+
HTMLLIElement,
38+
React.ComponentPropsWithoutRef<"li">
39+
>(({ className, ...props }, ref) => (
40+
<li ref={ref} className={cn("inline-flex items-center", className)} {...props} />
41+
))
42+
BreadcrumbItem.displayName = "BreadcrumbItem"
43+
44+
const BreadcrumbLink = React.forwardRef<
45+
HTMLAnchorElement,
46+
React.ComponentPropsWithoutRef<"a"> & { asChild?: boolean }
47+
>(({ asChild, className, ...props }, ref) => {
48+
const Comp = asChild ? Slot : "a"
49+
return (
50+
<Comp
51+
ref={ref}
52+
className={cn(
53+
"font-medium transition-colors hover:text-foreground focus:outline-none focus:ring-2 focus:ring-ring rounded-sm",
54+
className
55+
)}
56+
{...props}
57+
/>
58+
)
59+
})
60+
BreadcrumbLink.displayName = "BreadcrumbLink"
61+
62+
const BreadcrumbPage = React.forwardRef<
63+
HTMLSpanElement,
64+
React.ComponentPropsWithoutRef<"span">
65+
>(({ className, ...props }, ref) => (
66+
<span
67+
ref={ref}
68+
role="link"
69+
aria-disabled="true"
70+
aria-current="page"
71+
className={cn("text-foreground font-semibold", className)}
72+
{...props}
73+
/>
74+
))
75+
BreadcrumbPage.displayName = "BreadcrumbPage"
76+
77+
const BreadcrumbSeparator = ({
78+
children,
79+
className,
80+
...props
81+
}: React.ComponentProps<"li">) => (
82+
<li
83+
role="presentation"
84+
aria-hidden="true"
85+
className={cn("text-muted-foreground [&>svg]:h-4 [&>svg]:w-4", className)}
86+
{...props}
87+
>
88+
{children ?? <ChevronRight />}
89+
</li>
90+
)
91+
BreadcrumbSeparator.displayName = "BreadcrumbSeparator"
92+
93+
const BreadcrumbEllipsis = ({
94+
className,
95+
...props
96+
}: React.ComponentProps<"span">) => (
97+
<span
98+
role="presentation"
99+
aria-hidden="true"
100+
className={cn("flex h-9 w-9 items-center justify-center", className)}
101+
{...props}
102+
>
103+
<MoreHorizontal className="h-4 w-4" />
104+
<span className="sr-only">More</span>
105+
</span>
106+
)
107+
BreadcrumbEllipsis.displayName = "BreadcrumbEllipsis"
108+
109+
const Breadcrumb = Object.assign(BreadcrumbRoot, {
110+
List: BreadcrumbList,
111+
Item: BreadcrumbItem,
112+
Link: BreadcrumbLink,
113+
Page: BreadcrumbPage,
114+
Separator: BreadcrumbSeparator,
115+
Ellipsis: BreadcrumbEllipsis,
116+
})
117+
118+
export { Breadcrumb }
119+
120+

components/retroui/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,4 @@ export * from "./Toggle";
2222
export * from "./ToggleGroup";
2323
export * from "./Sonner";
2424
export * from "./Tooltip";
25+
export * from "./Breadcrumb";

config/components.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,10 @@ export const componentConfig: {
108108
name: "tooltip",
109109
filePath: "components/retroui/Tooltip.tsx",
110110
},
111+
breadcrumb: {
112+
name: "breadcrumb",
113+
filePath: "components/retroui/Breadcrumb.tsx",
114+
}
111115
},
112116
examples: {
113117
"accordion-style-default": {
@@ -469,5 +473,33 @@ export const componentConfig: {
469473
() => import("@/preview/components/toggle-group-style-solid"),
470474
),
471475
},
476+
"breadcrumb-style-default": {
477+
name: "breadcrumb-style-default",
478+
filePath: "preview/components/breadcrumb-style-default.tsx",
479+
preview: lazy(
480+
() => import("@/preview/components/breadcrumb-style-default"),
481+
),
482+
},
483+
"breadcrumb-custom-separator": {
484+
name: "breadcrumb-custom-separator",
485+
filePath: "preview/components/breadcrumb-custom-separator.tsx",
486+
preview: lazy(
487+
() => import("@/preview/components/breadcrumb-custom-separator"),
488+
),
489+
},
490+
"breadcrumb-style-collapsed": {
491+
name: "breadcrumb-style-collapsed",
492+
filePath: "preview/components/breadcrumb-style-collapsed.tsx",
493+
preview: lazy(
494+
() => import("@/preview/components/breadcrumb-style-collapsed"),
495+
),
496+
},
497+
"breadcrumb-link-component": {
498+
name: "breadcrumb-link-component",
499+
filePath: "preview/components/breadcrumb-link-component.tsx",
500+
preview: lazy(
501+
() => import("@/preview/components/breadcrumb-link-component"),
502+
),
503+
},
472504
},
473505
};

config/navigation.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ export const navConfig: INavigationConfig = {
2828
{ title: "Alert", href: `${componentsRoute}/alert` },
2929
{ title: "Avatar", href: `${componentsRoute}/avatar` },
3030
{ title: "Badge", href: `${componentsRoute}/badge` },
31+
{ title: "Breadcrumb", href: `${componentsRoute}/breadcrumb` },
3132
{ title: "Button", href: `${componentsRoute}/button` },
3233
{ title: "Card", href: `${componentsRoute}/card` },
3334
{ title: "Checkbox", href: `${componentsRoute}/checkbox` },
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
---
2+
title: Breadcrumb
3+
description: A navigation component that shows users where they are within a hierarchy.
4+
lastUpdated: 12 May, 2025
5+
---
6+
7+
<ComponentShowcase name="breadcrumb-style-default" />
8+
<br />
9+
<br />
10+
11+
<ComponentInstall>
12+
<ComponentInstall.Cli>
13+
```sh
14+
npx shadcn@latest add "https://retroui.dev/r/badge.json"
15+
```
16+
</ComponentInstall.Cli>
17+
<ComponentInstall.Manual>
18+
#### 1. Install dependencies:
19+
20+
```sh
21+
npm install lucide-react class-variance-authority
22+
````
23+
24+
<br />
25+
26+
#### 2. Copy the code 👇 into your project:
27+
28+
<ComponentSource name="breadcrumb" />
29+
30+
</ComponentInstall.Manual>
31+
</ComponentInstall>
32+
33+
<br />
34+
<br />
35+
36+
## Examples
37+
38+
### Default
39+
40+
<hr />
41+
<br />
42+
<ComponentShowcase name="breadcrumb-style-default" />
43+
<br />
44+
<br />
45+
46+
### Custom Separator
47+
48+
<hr />
49+
<br />
50+
<ComponentShowcase name="breadcrumb-custom-separator" />
51+
<br />
52+
<br />
53+
54+
### Collapsed
55+
56+
<hr />
57+
<br />
58+
<ComponentShowcase name="breadcrumb-style-collapsed" />
59+
<br />
60+
<br />
61+
62+
### Link Component
63+
64+
<hr />
65+
<br />
66+
<ComponentShowcase name="breadcrumb-link-component" />
67+
<br />
68+
<br />

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
"@radix-ui/react-radio-group": "^1.2.3",
2323
"@radix-ui/react-select": "^2.1.6",
2424
"@radix-ui/react-slider": "^1.2.4",
25+
"@radix-ui/react-slot": "^1.2.2",
2526
"@radix-ui/react-switch": "^1.1.3",
2627
"@radix-ui/react-toggle": "^1.1.6",
2728
"@radix-ui/react-toggle-group": "^1.1.7",

pnpm-lock.yaml

Lines changed: 19 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { Breadcrumb } from "@/components/retroui/Breadcrumb";
2+
import { Slash } from "lucide-react";
3+
4+
export default function BreadcrumbCustomSeparator() {
5+
return (
6+
<Breadcrumb>
7+
<Breadcrumb.List>
8+
<Breadcrumb.Item>
9+
<Breadcrumb.Link href="/">Home</Breadcrumb.Link>
10+
</Breadcrumb.Item>
11+
<Breadcrumb.Separator>
12+
<Slash />
13+
</Breadcrumb.Separator>
14+
<Breadcrumb.Item>
15+
<Breadcrumb.Link href="/components">Components</Breadcrumb.Link>
16+
</Breadcrumb.Item>
17+
<Breadcrumb.Separator>
18+
<Slash />
19+
</Breadcrumb.Separator>
20+
<Breadcrumb.Item>
21+
<Breadcrumb.Page>Breadcrumb</Breadcrumb.Page>
22+
</Breadcrumb.Item>
23+
</Breadcrumb.List>
24+
</Breadcrumb>
25+
);
26+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import Link from "next/link"
2+
3+
import { Breadcrumb } from "@/components/retroui/Breadcrumb"
4+
5+
export default function BreadcrumbLinkComponent() {
6+
return (
7+
<Breadcrumb>
8+
<Breadcrumb.List>
9+
<Breadcrumb.Item>
10+
<Breadcrumb.Link asChild>
11+
<Link href="/">Home</Link>
12+
</Breadcrumb.Link>
13+
</Breadcrumb.Item>
14+
<Breadcrumb.Separator />
15+
<Breadcrumb.Item>
16+
<Breadcrumb.Link asChild>
17+
<Link href="/docs/components">Components</Link>
18+
</Breadcrumb.Link>
19+
</Breadcrumb.Item>
20+
<Breadcrumb.Separator />
21+
<Breadcrumb.Item>
22+
<Breadcrumb.Page>Breadcrumb</Breadcrumb.Page>
23+
</Breadcrumb.Item>
24+
</Breadcrumb.List>
25+
</Breadcrumb>
26+
)
27+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import Link from "next/link"
2+
3+
import { Breadcrumb } from "@/components/retroui/Breadcrumb";
4+
5+
export default function BreadcrumbCollapsed() {
6+
return (
7+
<Breadcrumb>
8+
<Breadcrumb.List>
9+
<Breadcrumb.Item>
10+
<Breadcrumb.Link asChild>
11+
<Link href="/">Home</Link>
12+
</Breadcrumb.Link>
13+
</Breadcrumb.Item>
14+
<Breadcrumb.Item>
15+
<Breadcrumb.Ellipsis />
16+
</Breadcrumb.Item>
17+
<Breadcrumb.Separator />
18+
<Breadcrumb.Item>
19+
<Breadcrumb.Link asChild>
20+
<Link href="/docs/components">Components</Link>
21+
</Breadcrumb.Link>
22+
</Breadcrumb.Item>
23+
<Breadcrumb.Separator />
24+
<Breadcrumb.Item>
25+
<Breadcrumb.Page>Breadcrumb</Breadcrumb.Page>
26+
</Breadcrumb.Item>
27+
</Breadcrumb.List>
28+
</Breadcrumb>
29+
)
30+
}

0 commit comments

Comments
 (0)