Breadcrumb
Displays the path to the current resource using a hierarchy of links.
import { css } from 'remix/component'
import {
Breadcrumb,
BreadcrumbEllipsis,
BreadcrumbItem,import { css } from 'remix/component'
import {
Breadcrumb,
BreadcrumbEllipsis,
BreadcrumbItem,
BreadcrumbLink,
BreadcrumbList,
BreadcrumbPage,
BreadcrumbSeparator,
} from '#app/ui/breadcrumb.tsx'
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from '#app/ui/dropdown-menu.tsx'
const triggerStyles = css({ display: 'flex', alignItems: 'center', gap: '0.25rem' })
const ellipsisStyles = css({ width: '1rem', height: '1rem' })
const srOnly = css({
position: 'absolute',
width: '1px',
height: '1px',
padding: 0,
margin: '-1px',
overflow: 'hidden',
clip: 'rect(0, 0, 0, 0)',
whiteSpace: 'nowrap',
borderWidth: 0,
})
export function BreadcrumbDemo() {
return () => (
<Breadcrumb>
<BreadcrumbList>
<BreadcrumbItem>
<BreadcrumbLink href="/">Home</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<DropdownMenu>
<DropdownMenuTrigger mix={triggerStyles}>
<BreadcrumbEllipsis mix={ellipsisStyles} />
<span mix={srOnly}>Toggle menu</span>
</DropdownMenuTrigger>
<DropdownMenuContent align="start">
<DropdownMenuItem>Documentation</DropdownMenuItem>
<DropdownMenuItem>Themes</DropdownMenuItem>
<DropdownMenuItem>GitHub</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbLink href="/docs/components">Components</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbPage>Breadcrumb</BreadcrumbPage>
</BreadcrumbItem>
</BreadcrumbList>
</Breadcrumb>
)
}Installation
$ bunx --bun shadcn@latest add https://www.shadcn-remix.com/r/breadcrumb.json$ npx shadcn@latest add https://www.shadcn-remix.com/r/breadcrumb.json$ pnpm dlx shadcn@latest add https://www.shadcn-remix.com/r/breadcrumb.json$ yarn dlx shadcn@latest add https://www.shadcn-remix.com/r/breadcrumb.jsonInstall the following dependencies:
$ bun add remix$ npm install remix$ pnpm add remix$ yarn add remixCopy and paste the following code into your project.
import { css, type Handle, type Props } from 'remix/component'
import { ChevronRightIcon, MoreHorizontalIcon } from './icons.tsx'
const srOnly = css({
position: 'absolute',
width: '1px',
height: '1px',
padding: 0,
margin: '-1px',
overflow: 'hidden',
clip: 'rect(0, 0, 0, 0)',
whiteSpace: 'nowrap',
borderWidth: 0,
})
const listStyles = css({
display: 'flex',
flexWrap: 'wrap',
alignItems: 'center',
gap: '0.375rem',
fontSize: '0.875rem',
lineHeight: 'calc(1.25 / 0.875)',
overflowWrap: 'break-word',
color: 'var(--muted-foreground)',
'@media (min-width: 40rem)': { gap: '0.625rem' },
})
const itemStyles = css({
display: 'inline-flex',
alignItems: 'center',
gap: '0.375rem',
})
const linkStyles = css({
transitionProperty: 'color, background-color, border-color, outline-color, text-decoration-color, fill, stroke',
transitionTimingFunction: 'cubic-bezier(0.4, 0, 0.2, 1)',
transitionDuration: '150ms',
'&:hover': { color: 'var(--foreground)' },
})
const pageStyles = css({
fontWeight: 400,
color: 'var(--foreground)',
})
const separatorStyles = css({
'& > svg': { width: '0.875rem', height: '0.875rem' },
})
const ellipsisStyles = css({
display: 'flex',
width: '2.25rem',
height: '2.25rem',
alignItems: 'center',
justifyContent: 'center',
})
const ellipsisIconStyles = css({ width: '1rem', height: '1rem' })
export function Breadcrumb(handle: Handle<Props<'nav'>>) {
return () => <nav aria-label="breadcrumb" data-slot="breadcrumb" {...handle.props} />
}
export function BreadcrumbList(handle: Handle<Props<'ol'>>) {
return () => {
let { mix, ...props } = handle.props
return <ol data-slot="breadcrumb-list" {...props} mix={[listStyles, mix]} />
}
}
export function BreadcrumbItem(handle: Handle<Props<'li'>>) {
return () => {
let { mix, ...props } = handle.props
return <li data-slot="breadcrumb-item" {...props} mix={[itemStyles, mix]} />
}
}
/**
* A breadcrumb `<a>`. Remix has no `asChild`: links are plain anchors, so pass `href` (and any
* other anchor attribute or mixin, e.g. `link(...)`) directly.
*/
export function BreadcrumbLink(handle: Handle<Props<'a'>>) {
return () => {
let { mix, ...props } = handle.props
return <a data-slot="breadcrumb-link" {...props} mix={[linkStyles, mix]} />
}
}
export function BreadcrumbPage(handle: Handle<Props<'span'>>) {
return () => {
let { mix, ...props } = handle.props
return (
<span
data-slot="breadcrumb-page"
role="link"
aria-disabled="true"
aria-current="page"
{...props}
mix={[pageStyles, mix]}
/>
)
}
}
export function BreadcrumbSeparator(handle: Handle<Props<'li'>>) {
return () => {
let { children, mix, ...props } = handle.props
return (
<li
data-slot="breadcrumb-separator"
role="presentation"
aria-hidden="true"
{...props}
mix={[separatorStyles, mix]}
>
{children ?? <ChevronRightIcon />}
</li>
)
}
}
export function BreadcrumbEllipsis(handle: Handle<Props<'span'>>) {
return () => {
let { mix, ...props } = handle.props
return (
<span
data-slot="breadcrumb-ellipsis"
role="presentation"
aria-hidden="true"
{...props}
mix={[ellipsisStyles, mix]}
>
<MoreHorizontalIcon mix={ellipsisIconStyles} />
<span mix={srOnly}>More</span>
</span>
)
}
}Update the import paths to match your project setup.
Usage
import {
Breadcrumb,
BreadcrumbItem,
BreadcrumbLink,
BreadcrumbList,
BreadcrumbPage,
BreadcrumbSeparator,
} from '#app/ui/breadcrumb.tsx'<Breadcrumb>
<BreadcrumbList>
<BreadcrumbItem>
<BreadcrumbLink href="/">Home</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbLink href="/components">Components</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbPage>Breadcrumb</BreadcrumbPage>
</BreadcrumbItem>
</BreadcrumbList>
</Breadcrumb>Examples
Custom separator
Use a custom component as children for <BreadcrumbSeparator /> to create a custom separator.
import {
Breadcrumb,
BreadcrumbItem,
BreadcrumbLink,
BreadcrumbList,
BreadcrumbPage,import {
Breadcrumb,
BreadcrumbItem,
BreadcrumbLink,
BreadcrumbList,
BreadcrumbPage,
BreadcrumbSeparator as BreadcrumbDivider,
} from '#app/ui/breadcrumb.tsx'
import { SlashIcon } from '#app/ui/icons.tsx'
export function BreadcrumbSeparator() {
return () => (
<Breadcrumb>
<BreadcrumbList>
<BreadcrumbItem>
<BreadcrumbLink href="/">Home</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbDivider>
<SlashIcon />
</BreadcrumbDivider>
<BreadcrumbItem>
<BreadcrumbLink href="/components">Components</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbDivider>
<SlashIcon />
</BreadcrumbDivider>
<BreadcrumbItem>
<BreadcrumbPage>Breadcrumb</BreadcrumbPage>
</BreadcrumbItem>
</BreadcrumbList>
</Breadcrumb>
)
}Dropdown
You can compose <BreadcrumbItem /> with a <DropdownMenu /> to create a dropdown in the breadcrumb.
import { css } from 'remix/component'
import {
Breadcrumb,
BreadcrumbItem,
BreadcrumbLink,import { css } from 'remix/component'
import {
Breadcrumb,
BreadcrumbItem,
BreadcrumbLink,
BreadcrumbList,
BreadcrumbPage,
BreadcrumbSeparator,
} from '#app/ui/breadcrumb.tsx'
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from '#app/ui/dropdown-menu.tsx'
import { ChevronDownIcon, SlashIcon } from '#app/ui/icons.tsx'
const triggerStyles = css({
display: 'flex',
alignItems: 'center',
gap: '0.25rem',
'& svg': { pointerEvents: 'none', flexShrink: 0 },
'& svg:not([class*="size-"])': { width: '0.875rem', height: '0.875rem' },
})
export function BreadcrumbDropdown() {
return () => (
<Breadcrumb>
<BreadcrumbList>
<BreadcrumbItem>
<BreadcrumbLink href="/">Home</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator>
<SlashIcon />
</BreadcrumbSeparator>
<BreadcrumbItem>
<DropdownMenu>
<DropdownMenuTrigger mix={triggerStyles}>
Components
<ChevronDownIcon />
</DropdownMenuTrigger>
<DropdownMenuContent align="start">
<DropdownMenuItem>Documentation</DropdownMenuItem>
<DropdownMenuItem>Themes</DropdownMenuItem>
<DropdownMenuItem>GitHub</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</BreadcrumbItem>
<BreadcrumbSeparator>
<SlashIcon />
</BreadcrumbSeparator>
<BreadcrumbItem>
<BreadcrumbPage>Breadcrumb</BreadcrumbPage>
</BreadcrumbItem>
</BreadcrumbList>
</Breadcrumb>
)
}Collapsed
We provide a <BreadcrumbEllipsis /> component to show a collapsed state when the breadcrumb is too long.
import {
Breadcrumb,
BreadcrumbEllipsis as BreadcrumbEllipsisIndicator,
BreadcrumbItem,
BreadcrumbLink,
BreadcrumbList,import {
Breadcrumb,
BreadcrumbEllipsis as BreadcrumbEllipsisIndicator,
BreadcrumbItem,
BreadcrumbLink,
BreadcrumbList,
BreadcrumbPage,
BreadcrumbSeparator,
} from '#app/ui/breadcrumb.tsx'
export function BreadcrumbEllipsis() {
return () => (
<Breadcrumb>
<BreadcrumbList>
<BreadcrumbItem>
<BreadcrumbLink href="/">Home</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbEllipsisIndicator />
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbLink href="/docs/components">Components</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbPage>Breadcrumb</BreadcrumbPage>
</BreadcrumbItem>
</BreadcrumbList>
</Breadcrumb>
)
}Link component
BreadcrumbLink is a plain <a>. Pass href and any anchor attributes, or apply its styles to your own element with mix.
import {
Breadcrumb,
BreadcrumbItem,
BreadcrumbLink as BreadcrumbAnchor,
BreadcrumbList,
BreadcrumbPage,import {
Breadcrumb,
BreadcrumbItem,
BreadcrumbLink as BreadcrumbAnchor,
BreadcrumbList,
BreadcrumbPage,
BreadcrumbSeparator,
} from '#app/ui/breadcrumb.tsx'
export function BreadcrumbLink() {
return () => (
<Breadcrumb>
<BreadcrumbList>
<BreadcrumbItem>
<BreadcrumbAnchor href="/">Home</BreadcrumbAnchor>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbAnchor href="/components">Components</BreadcrumbAnchor>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbPage>Breadcrumb</BreadcrumbPage>
</BreadcrumbItem>
</BreadcrumbList>
</Breadcrumb>
)
}API Reference
Breadcrumb
| Prop | Type | Default |
|---|---|---|
mix | MixValue | - |
BreadcrumbList
| Prop | Type | Default |
|---|---|---|
mix | MixValue | - |
BreadcrumbItem
| Prop | Type | Default |
|---|---|---|
mix | MixValue | - |
BreadcrumbLink
A breadcrumb <a>. Remix has no asChild: links are plain anchors, so pass href (and any other anchor attribute or mixin, e.g. link(...)) directly.
| Prop | Type | Default |
|---|---|---|
mix | MixValue | - |
BreadcrumbPage
| Prop | Type | Default |
|---|---|---|
mix | MixValue | - |
BreadcrumbSeparator
| Prop | Type | Default |
|---|---|---|
mix | MixValue | - |
BreadcrumbEllipsis
| Prop | Type | Default |
|---|---|---|
mix | MixValue | - |