A hierarchy of links to the current page in an application.
function Example() { const items = [ {id: 1, label: 'Home', href: '/'}, {id: 2, label: 'Navigation', href: '/components/navigation'}, {id: 3, label: 'Breadcrumbs', href: '/components/navigation/breadcrumbs'}, ]
return <Breadcrumbs items={items} />}Here's the <Breadcrumbs /> component in action.
import { forwardRef, type ElementRef } from 'react'import { Breadcrumbs as ReactAriaBreadcrumbs, Breadcrumb, Link, type BreadcrumbsProps } from 'react-aria-components'import { Icon } from '#app/old_components/ui/icon.tsx'import { cn } from '#app/utils/tailwind-merge.ts'
type Breadcrumb = { href: string label: string}
type BreadcrumbItem = Breadcrumb & { id: string | number}
const Breadcrumbs = forwardRef<ElementRef<typeof ReactAriaBreadcrumbs>, BreadcrumbsProps<BreadcrumbItem>>(({ className, ...props }, ref) => { return ( <ReactAriaBreadcrumbs ref={ref} className={cn('breadcrumbs', className)} {...props}> {({ id, href, label }: BreadcrumbItem) => ( <Breadcrumb key={id} className="breadcrumb"> <Link className="peer" href={href}> {label} </Link> <Icon name="chevron-right" aria-hidden="true" className="icon peer-data-[current]:hidden" /> </Breadcrumb> )} </ReactAriaBreadcrumbs> )})Breadcrumbs.displayName = 'Breadcrumbs'
export { Breadcrumbs, type Breadcrumb, type BreadcrumbItem }
/* ### Navigation ### */@layer components { .breadcrumbs { @apply flex flex-wrap;
& .breadcrumb { @apply flex items-center;
& a { @apply p-1 text-foreground opacity-50 data-[disabled]:opacity-100; }
& .icon { @apply h-4 w-4 opacity-50; } } }}The <Breadcrumbs /> component receives an array of items to render as links. But it's up to you to figure out how to generate the items array based on your framework.
I suggest you create an additional component that encapsulates this logic.
Here's how you'd do it in Remix:
import { useMatches } from '@remix-run/react'import { type ElementRef, forwardRef } from 'react'import { type BreadcrumbsProps } from 'react-aria-components'import { type BreadcrumbItem, Breadcrumbs } from './breadcrumbs.tsx'
const RemixBreadcrumbs = forwardRef<ElementRef<typeof Breadcrumbs>, BreadcrumbsProps<BreadcrumbItem>>(({ ...props }, ref) => { const matches = useMatches() const items: BreadcrumbItem[] = matches .filter(match => match.handle && (match.handle as { breadcrumb: BreadcrumbItem }).breadcrumb) .map(match => { const { id } = match const { href, label } = (match.handle as { breadcrumb: BreadcrumbItem }).breadcrumb return { id, href, label } }) return <Breadcrumbs ref={ref} items={items} {...props} />})RemixBreadcrumbs.displayName = 'RemixBreadcrumbs'
export { RemixBreadcrumbs }Then, just place this <RemixBreadcrumbs /> component wherever you want breadcrumbs to show up in your app.
Remember that, in Remix, each route decides if and how it will contribute to the breadcrumbs using a handle export.
export const handle = { breadcrumb: () => <Link to="/parent">Some Route</Link>,}