# Breadcrumb

Displays the path to the current resource using a hierarchy of links.

```tsx
import {
  Breadcrumb,
  BreadcrumbEllipsis,
  BreadcrumbItem,
  BreadcrumbLink,
  BreadcrumbList,
  BreadcrumbPage,
  BreadcrumbSeparator,
} from "@/components/ui/breadcrumb"
import { Button } from "@/components/ui/button"
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuGroup,
  DropdownMenuItem,
  DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"

export default function BreadcrumbDemo() {
  return (
    <Breadcrumb>
      <BreadcrumbList>
        <BreadcrumbItem>
          <BreadcrumbLink href="#">Home</BreadcrumbLink>
        </BreadcrumbItem>
        <BreadcrumbSeparator />
        <BreadcrumbItem>
          <DropdownMenu>
            <DropdownMenuTrigger
              render={<Button variant="ghost" size="icon-sm" aria-label="Toggle menu" />}
            >
              <BreadcrumbEllipsis />
            </DropdownMenuTrigger>
            <DropdownMenuContent align="start">
              <DropdownMenuGroup>
                <DropdownMenuItem>Documentation</DropdownMenuItem>
                <DropdownMenuItem>Themes</DropdownMenuItem>
                <DropdownMenuItem>GitHub</DropdownMenuItem>
              </DropdownMenuGroup>
            </DropdownMenuContent>
          </DropdownMenu>
        </BreadcrumbItem>
        <BreadcrumbSeparator />
        <BreadcrumbItem>
          <BreadcrumbLink href="#">Components</BreadcrumbLink>
        </BreadcrumbItem>
        <BreadcrumbSeparator />
        <BreadcrumbItem>
          <BreadcrumbPage>Breadcrumb</BreadcrumbPage>
        </BreadcrumbItem>
      </BreadcrumbList>
    </Breadcrumb>
  )
}
```

## Installation

1. Install the following dependencies:

   ```bash
   npm install @base-ui/react @stylexjs/stylex clsx lucide-react
   ```

2. Set up the token layer and the StyleX compiler, if you have not already. See
   [Installation](https://carbon.style/docs/installation). The breadcrumb also needs `interop.css`,
   which sizes the separator and ellipsis icons.

3. Copy and paste the following code into your project.

   ```tsx title="components/ui/breadcrumb.tsx"
   "use client"

   import { useRender } from "@base-ui/react/use-render"
   import * as stylex from "@stylexjs/stylex"
   import type { StyleXStyles } from "@stylexjs/stylex"
   import { clsx } from "clsx"
   import { ChevronRight, MoreHorizontal } from "lucide-react"

   import { color, duration, ease, leading, radius, space, text } from "@/theme/tokens.stylex"

   const styles = stylex.create({
     list: {
       display: "flex",
       flexWrap: "wrap",
       alignItems: "center",
       columnGap: space.s1_5,
       rowGap: space.s1_5,
       listStyleType: "none",
       overflowWrap: "break-word",
       color: color.mutedForeground,
       fontSize: text.sm,
       lineHeight: leading.sm,
     },
     item: { display: "inline-flex", alignItems: "center", gap: space.s1 },
     link: {
       borderRadius: radius.sm,
       color: { default: null, ":hover": color.foreground },
       outlineColor: color.ring,
       outlineWidth: 2,
       outlineOffset: 2,
       outlineStyle: { default: "none", ":focus-visible": "solid" },
       transitionProperty: "color",
       transitionDuration: duration.color,
       transitionTimingFunction: ease.standard,
     },
     page: { color: color.foreground, fontWeight: 400 },
     separator: {
       display: "inline-flex",
       alignItems: "center",
       "--carbon-icon-size": space.s3_5,
     },
     ellipsis: {
       display: "flex",
       alignItems: "center",
       justifyContent: "center",
       width: space.s5,
       height: space.s5,
       "--carbon-icon-size": space.s4,
     },
   })

   const breadcrumbStyles = {
     list: styles.list,
     item: styles.item,
     link: styles.link,
     page: styles.page,
     separator: styles.separator,
     ellipsis: styles.ellipsis,
   }

   type Overrides = { xstyle?: StyleXStyles; className?: string }

   function Breadcrumb({
     render,
     ref,
     style,
     xstyle,
     className,
     ...props
   }: useRender.ComponentProps<"nav"> & Overrides) {
     const sx = stylex.props(xstyle)
     return useRender({
       defaultTagName: "nav",
       render,
       ref,
       props: {
         "aria-label": "breadcrumb",
         "data-slot": "breadcrumb",
         ...sx,
         ...props,
         className: clsx(sx.className, className),
         style: { ...sx.style, ...style },
       },
     })
   }

   function BreadcrumbList({
     render,
     ref,
     style,
     xstyle,
     className,
     ...props
   }: useRender.ComponentProps<"ol"> & Overrides) {
     const sx = stylex.props(styles.list, xstyle)
     return useRender({
       defaultTagName: "ol",
       render,
       ref,
       props: {
         "data-slot": "breadcrumb-list",
         ...sx,
         ...props,
         className: clsx(sx.className, className),
         style: { ...sx.style, ...style },
       },
     })
   }

   function BreadcrumbItem({
     render,
     ref,
     style,
     xstyle,
     className,
     ...props
   }: useRender.ComponentProps<"li"> & Overrides) {
     const sx = stylex.props(styles.item, xstyle)
     return useRender({
       defaultTagName: "li",
       render,
       ref,
       props: {
         "data-slot": "breadcrumb-item",
         ...sx,
         ...props,
         className: clsx(sx.className, className),
         style: { ...sx.style, ...style },
       },
     })
   }

   type BreadcrumbLinkProps = useRender.ComponentProps<"a"> & { xstyle?: StyleXStyles }

   function BreadcrumbLink({ xstyle, className, render, ...props }: BreadcrumbLinkProps) {
     const sx = stylex.props(styles.link, xstyle)
     return useRender({
       defaultTagName: "a",
       render,
       props: {
         "data-slot": "breadcrumb-link",
         ...sx,
         ...props,
         className: clsx(sx.className, className),
       },
     })
   }

   function BreadcrumbPage({
     render,
     ref,
     style,
     xstyle,
     className,
     ...props
   }: useRender.ComponentProps<"span"> & Overrides) {
     const sx = stylex.props(styles.page, xstyle)
     return useRender({
       defaultTagName: "span",
       render,
       ref,
       props: {
         "data-slot": "breadcrumb-page",
         role: "link",
         "aria-disabled": "true",
         "aria-current": "page",
         ...sx,
         ...props,
         className: clsx(sx.className, className),
         style: { ...sx.style, ...style },
       },
     })
   }

   function BreadcrumbSeparator({
     render,
     ref,
     style,
     children,
     xstyle,
     className,
     ...props
   }: useRender.ComponentProps<"li"> & Overrides) {
     const sx = stylex.props(styles.separator, xstyle)
     return useRender({
       defaultTagName: "li",
       render,
       ref,
       props: {
         "data-slot": "breadcrumb-separator",
         role: "presentation",
         "aria-hidden": "true",
         ...sx,
         ...props,
         className: clsx("carbon-icons", sx.className, className),
         style: { ...sx.style, ...style },
         children: <>{children ?? <ChevronRight />}</>,
       },
     })
   }

   function BreadcrumbEllipsis({
     render,
     ref,
     style,
     xstyle,
     className,
     ...props
   }: useRender.ComponentProps<"span"> & Overrides) {
     const sx = stylex.props(styles.ellipsis, xstyle)
     return useRender({
       defaultTagName: "span",
       render,
       ref,
       props: {
         "data-slot": "breadcrumb-ellipsis",
         role: "presentation",
         "aria-hidden": "true",
         ...sx,
         ...props,
         className: clsx("carbon-icons", sx.className, className),
         style: { ...sx.style, ...style },
         children: (
           <>
             <MoreHorizontal />
           </>
         ),
       },
     })
   }

   export {
     Breadcrumb,
     BreadcrumbEllipsis,
     BreadcrumbItem,
     BreadcrumbLink,
     BreadcrumbList,
     BreadcrumbPage,
     BreadcrumbSeparator,
     breadcrumbStyles,
   }
   ```

4. Update the import paths to match your project setup.

## Usage

```tsx
import {
  Breadcrumb,
  BreadcrumbItem,
  BreadcrumbLink,
  BreadcrumbList,
  BreadcrumbPage,
  BreadcrumbSeparator,
} from "@/components/ui/breadcrumb"
```

```tsx
<Breadcrumb>
  <BreadcrumbList>
    <BreadcrumbItem>
      <BreadcrumbLink href="/">Home</BreadcrumbLink>
    </BreadcrumbItem>
    <BreadcrumbSeparator />
    <BreadcrumbItem>
      <BreadcrumbPage>Breadcrumb</BreadcrumbPage>
    </BreadcrumbItem>
  </BreadcrumbList>
</Breadcrumb>
```

## Composition

```text
Breadcrumb
└── BreadcrumbList
    ├── BreadcrumbItem
    │   └── BreadcrumbLink
    ├── BreadcrumbSeparator
    └── BreadcrumbItem
        └── BreadcrumbPage
```

## Basic

A trail of links ending in the current page.

```tsx
import {
  Breadcrumb,
  BreadcrumbItem,
  BreadcrumbLink,
  BreadcrumbList,
  BreadcrumbPage,
  BreadcrumbSeparator,
} from "@/components/ui/breadcrumb"

export default function BreadcrumbBasic() {
  return (
    <Breadcrumb>
      <BreadcrumbList>
        <BreadcrumbItem>
          <BreadcrumbLink href="#">Home</BreadcrumbLink>
        </BreadcrumbItem>
        <BreadcrumbSeparator />
        <BreadcrumbItem>
          <BreadcrumbLink href="#">Components</BreadcrumbLink>
        </BreadcrumbItem>
        <BreadcrumbSeparator />
        <BreadcrumbItem>
          <BreadcrumbPage>Breadcrumb</BreadcrumbPage>
        </BreadcrumbItem>
      </BreadcrumbList>
    </Breadcrumb>
  )
}
```

## Custom separator

Pass `children` to `BreadcrumbSeparator` to replace the chevron.

```tsx
import {
  Breadcrumb,
  BreadcrumbItem,
  BreadcrumbLink,
  BreadcrumbList,
  BreadcrumbPage,
  BreadcrumbSeparator,
} from "@/components/ui/breadcrumb"
import { Slash } from "lucide-react"

export default function BreadcrumbSeparatorDemo() {
  return (
    <Breadcrumb>
      <BreadcrumbList>
        <BreadcrumbItem>
          <BreadcrumbLink href="#">Home</BreadcrumbLink>
        </BreadcrumbItem>
        <BreadcrumbSeparator>
          <Slash />
        </BreadcrumbSeparator>
        <BreadcrumbItem>
          <BreadcrumbLink href="#">Components</BreadcrumbLink>
        </BreadcrumbItem>
        <BreadcrumbSeparator>
          <Slash />
        </BreadcrumbSeparator>
        <BreadcrumbItem>
          <BreadcrumbPage>Breadcrumb</BreadcrumbPage>
        </BreadcrumbItem>
      </BreadcrumbList>
    </Breadcrumb>
  )
}
```

## Dropdown

Put a `DropdownMenu` inside a `BreadcrumbItem` to branch off a segment.

```tsx
import * as stylex from "@stylexjs/stylex"
import {
  Breadcrumb,
  BreadcrumbItem,
  BreadcrumbLink,
  BreadcrumbList,
  BreadcrumbPage,
  BreadcrumbSeparator,
} from "@/components/ui/breadcrumb"
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuGroup,
  DropdownMenuItem,
  DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
import { color, space } from "@/theme/tokens.stylex"
import { ChevronDown } from "lucide-react"

const styles = stylex.create({
  trigger: {
    display: "inline-flex",
    alignItems: "center",
    gap: space.s1,
    color: { default: null, ":hover": color.foreground },
  },
  chevron: { width: space.s3_5, height: space.s3_5 },
})

export default function BreadcrumbDropdown() {
  return (
    <Breadcrumb>
      <BreadcrumbList>
        <BreadcrumbItem>
          <BreadcrumbLink href="#">Home</BreadcrumbLink>
        </BreadcrumbItem>
        <BreadcrumbSeparator />
        <BreadcrumbItem>
          <DropdownMenu>
            <DropdownMenuTrigger {...stylex.props(styles.trigger)}>
              Components
              <ChevronDown {...stylex.props(styles.chevron)} />
            </DropdownMenuTrigger>
            <DropdownMenuContent align="start">
              <DropdownMenuGroup>
                <DropdownMenuItem>Documentation</DropdownMenuItem>
                <DropdownMenuItem>Themes</DropdownMenuItem>
                <DropdownMenuItem>GitHub</DropdownMenuItem>
              </DropdownMenuGroup>
            </DropdownMenuContent>
          </DropdownMenu>
        </BreadcrumbItem>
        <BreadcrumbSeparator />
        <BreadcrumbItem>
          <BreadcrumbPage>Breadcrumb</BreadcrumbPage>
        </BreadcrumbItem>
      </BreadcrumbList>
    </Breadcrumb>
  )
}
```

## Collapsed

Use `BreadcrumbEllipsis` to stand in for the segments a long trail hides.

```tsx
import {
  Breadcrumb,
  BreadcrumbEllipsis,
  BreadcrumbItem,
  BreadcrumbLink,
  BreadcrumbList,
  BreadcrumbPage,
  BreadcrumbSeparator,
} from "@/components/ui/breadcrumb"

export default function BreadcrumbEllipsisDemo() {
  return (
    <Breadcrumb>
      <BreadcrumbList>
        <BreadcrumbItem>
          <BreadcrumbLink href="#">Home</BreadcrumbLink>
        </BreadcrumbItem>
        <BreadcrumbSeparator />
        <BreadcrumbItem>
          <BreadcrumbEllipsis />
        </BreadcrumbItem>
        <BreadcrumbSeparator />
        <BreadcrumbItem>
          <BreadcrumbLink href="#">Components</BreadcrumbLink>
        </BreadcrumbItem>
        <BreadcrumbSeparator />
        <BreadcrumbItem>
          <BreadcrumbPage>Breadcrumb</BreadcrumbPage>
        </BreadcrumbItem>
      </BreadcrumbList>
    </Breadcrumb>
  )
}
```

> **Note**
>
> `BreadcrumbEllipsis` is `aria-hidden` and has no accessible name. When it
> triggers a menu, put an `aria-label` on the control around it.

## Link component

Pass a router link through `render` on `BreadcrumbLink`. `BreadcrumbLink` then
applies its styles and props to your link instead of an `a`.

```tsx
import { Link } from "@tanstack/react-router"
```

```tsx
<BreadcrumbLink render={<Link to="/docs" />}>Docs</BreadcrumbLink>
```

## API reference

Pass `render` to replace a part's element or compose it with another component.

Every part takes `xstyle` and `className`.

### Breadcrumb

The `nav` landmark. It renders `aria-label="breadcrumb"` and carries no styling
of its own, so a list can be rendered without it.

### BreadcrumbLink

Renders an `a` and accepts its props.

| Prop     | Type              | Default |
| -------- | ----------------- | ------- |
| `render` | `React.ReactNode` | `<a />` |

### BreadcrumbSeparator

Renders an `li` marked `role="presentation"`.

| Prop       | Type              | Default            |
| ---------- | ----------------- | ------------------ |
| `children` | `React.ReactNode` | `<ChevronRight />` |

### breadcrumbStyles

The style map behind the component, exported so the same look can go on any
element.

| Key         | Description                           |
| ----------- | ------------------------------------- |
| `list`      | The wrapping row, its type and colour |
| `item`      | One segment's inline box              |
| `link`      | The hover colour and the focus ring   |
| `page`      | The current segment                   |
| `separator` | The separator's icon size             |
| `ellipsis`  | The ellipsis box and its icon size    |

### Data attributes

| Attribute                          | On            | Effect                                       |
| ---------------------------------- | ------------- | -------------------------------------------- |
| `data-slot="breadcrumb"`           | the nav       | Targets the landmark from a parent           |
| `data-slot="breadcrumb-list"`      | the list      | Targets the row                              |
| `data-slot="breadcrumb-item"`      | an item       | Targets one segment                          |
| `data-slot="breadcrumb-link"`      | a link        | Present on whatever `render` produces        |
| `data-slot="breadcrumb-page"`      | the last item | Also carries `aria-current="page"`           |
| `data-slot="breadcrumb-separator"` | the separator | Also `role="presentation"` and `aria-hidden` |
| `data-slot="breadcrumb-ellipsis"`  | the ellipsis  | Also `role="presentation"` and `aria-hidden` |

The separator and the ellipsis carry the `carbon-icons` class and set
`--carbon-icon-size`, which is how `interop.css` sizes the icon inside each.
