Breadcrumbs

A hierarchy of links to the current page in an application.

Features

  • Implemented as an ordered list of links.
  • The last link is automatically marked as the current page using aria-current.
  • Hover, press, and keyboard focus states are provided for easy styling.

Usage

BreadcrumbsExample.tsx
  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
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.

Source

Styling

tailwind.css
  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  14. 14
  15. 15
  16. 16
  17. 17
  18. 18
/* ### 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;
}
}
}
}

Notes

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:

RemixBreadcrumbs.tsx
  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  14. 14
  15. 15
  16. 16
  17. 17
  18. 18
  19. 19
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.

RemixBreadcrumbs.tsx
  1. 1
  2. 2
  3. 3
export const handle = {
breadcrumb: () => <Link to="/parent">Some Route</Link>,
}