Kosmesis
Components

Breadcrumb

A breadcrumb trail with separators and an ellipsis. Purely presentational.

Installation

npx kosmesis add breadcrumb
pnpm dlx kosmesis add breadcrumb
yarn dlx kosmesis add breadcrumb
bunx kosmesis add breadcrumb

Copy and paste the following code into your project.

breadcrumb.tsx
import { StatelessComponent } from "@praxisjs/core";import { Component } from "@praxisjs/decorators";import type { Children } from "@praxisjs/shared";import { cn } from "@/lib/utils";export interface BreadcrumbProps {  class?: string;  "aria-label"?: string;  children?: Children;}/** Purely presentational — no Morphos equivalent, same as upstream shadcn/ui. */@Component()export class Breadcrumb extends StatelessComponent<BreadcrumbProps> {  render() {    const { class: cls, "aria-label": ariaLabel = "breadcrumb", children } = this.props;    return (      <nav aria-label={ariaLabel} class={cls}>        {children}      </nav>    );  }}export interface BreadcrumbListProps {  class?: string;  children?: Children;}@Component()export class BreadcrumbList extends StatelessComponent<BreadcrumbListProps> {  render() {    const { class: cls, children } = this.props;    return (      <ol        class={cn(          "flex flex-wrap items-center gap-1.5 text-sm break-words text-muted-foreground sm:gap-2.5",          cls,        )}      >        {children}      </ol>    );  }}@Component()export class BreadcrumbItem extends StatelessComponent<BreadcrumbListProps> {  render() {    const { class: cls, children } = this.props;    return <li class={cn("inline-flex items-center gap-1.5", cls)}>{children}</li>;  }}export interface BreadcrumbLinkProps {  href?: string;  onClick?: (event: MouseEvent) => void;  class?: string;  children?: Children;}@Component()export class BreadcrumbLink extends StatelessComponent<BreadcrumbLinkProps> {  render() {    const { href, onClick, class: cls, children } = this.props;    return (      <a href={href} onClick={onClick} class={cn("transition-colors hover:text-foreground", cls)}>        {children}      </a>    );  }}@Component()export class BreadcrumbPage extends StatelessComponent<BreadcrumbListProps> {  render() {    const { class: cls, children } = this.props;    return (      <span role="link" aria-disabled={"true" as const} aria-current="page" class={cn("font-normal text-foreground", cls)}>        {children}      </span>    );  }}@Component()export class BreadcrumbSeparator extends StatelessComponent<BreadcrumbListProps> {  render() {    const { class: cls, children } = this.props;    return (      <li role="presentation" aria-hidden={"true" as const} class={cn("[&>svg]:size-3.5", cls)}>        {children ?? "/"}      </li>    );  }}@Component()export class BreadcrumbEllipsis extends StatelessComponent<{ class?: string }> {  render() {    const { class: cls } = this.props;    return (      <span role="presentation" aria-hidden={"true" as const} class={cn("flex size-9 items-center justify-center", cls)}>      </span>    );  }}

Install the following dependencies:

npm install @praxisjs/css
pnpm add @praxisjs/css
yarn add @praxisjs/css
bun add @praxisjs/css

Copy and paste the following code into your project.

breadcrumb.tsx
import { StatelessComponent } from "@praxisjs/core";import { cx, Stylesheet, Styled, tokenVars } from "@praxisjs/css";import { Component } from "@praxisjs/decorators";import type { Children } from "@praxisjs/shared";import { KosmesisTokens } from "@/lib/kosmesis-theme";const t = tokenVars(KosmesisTokens);class BreadcrumbStyles extends Stylesheet {  $list = this.css({    display: "flex",    flexWrap: "wrap",    alignItems: "center",    gap: "0.375rem",    fontSize: "0.875rem",    wordBreak: "break-word",    color: t.mutedForeground,  }).media("(min-width: 640px)", { gap: "0.625rem" });  $item = this.css({ display: "inline-flex", alignItems: "center", gap: "0.375rem" });  $link = this.css({ transition: "color 120ms ease" }).hover({ color: t.foreground });  $page = this.css({ fontWeight: 400, color: t.foreground });  $separator = this.css({}).on("& > svg", { width: "0.875rem", height: "0.875rem" });  $ellipsis = this.css({ display: "flex", width: "2.25rem", height: "2.25rem", alignItems: "center", justifyContent: "center" });}export interface BreadcrumbProps {  class?: string;  "aria-label"?: string;  children?: Children;}/** Purely presentational — no Morphos equivalent, same as upstream shadcn/ui. */@Component()export class Breadcrumb extends StatelessComponent<BreadcrumbProps> {  render() {    const { class: cls, "aria-label": ariaLabel = "breadcrumb", children } = this.props;    return (      <nav aria-label={ariaLabel} class={cls}>        {children}      </nav>    );  }}export interface BreadcrumbListProps {  class?: string;  children?: Children;}@Component()export class BreadcrumbList extends StatelessComponent<BreadcrumbListProps> {  @Styled(BreadcrumbStyles) $s!: BreadcrumbStyles;  render() {    const { class: cls, children } = this.props;    return <ol class={cx(this.$s.$list, cls)}>{children}</ol>;  }}@Component()export class BreadcrumbItem extends StatelessComponent<BreadcrumbListProps> {  @Styled(BreadcrumbStyles) $s!: BreadcrumbStyles;  render() {    const { class: cls, children } = this.props;    return <li class={cx(this.$s.$item, cls)}>{children}</li>;  }}export interface BreadcrumbLinkProps {  href?: string;  onClick?: (event: MouseEvent) => void;  class?: string;  children?: Children;}@Component()export class BreadcrumbLink extends StatelessComponent<BreadcrumbLinkProps> {  @Styled(BreadcrumbStyles) $s!: BreadcrumbStyles;  render() {    const { href, onClick, class: cls, children } = this.props;    return (      <a href={href} onClick={onClick} class={cx(this.$s.$link, cls)}>        {children}      </a>    );  }}@Component()export class BreadcrumbPage extends StatelessComponent<BreadcrumbListProps> {  @Styled(BreadcrumbStyles) $s!: BreadcrumbStyles;  render() {    const { class: cls, children } = this.props;    return (      <span role="link" aria-disabled={"true" as const} aria-current="page" class={cx(this.$s.$page, cls)}>        {children}      </span>    );  }}@Component()export class BreadcrumbSeparator extends StatelessComponent<BreadcrumbListProps> {  @Styled(BreadcrumbStyles) $s!: BreadcrumbStyles;  render() {    const { class: cls, children } = this.props;    return (      <li role="presentation" aria-hidden={"true" as const} class={cx(this.$s.$separator, cls)}>        {children ?? "/"}      </li>    );  }}@Component()export class BreadcrumbEllipsis extends StatelessComponent<{ class?: string }> {  @Styled(BreadcrumbStyles) $s!: BreadcrumbStyles;  render() {    const { class: cls } = this.props;    return (      <span role="presentation" aria-hidden={"true" as const} class={cx(this.$s.$ellipsis, cls)}>      </span>    );  }}

Examples

Usage

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

<Breadcrumb>
  <BreadcrumbList>
    <BreadcrumbItem>
      <BreadcrumbLink href="/">Home</BreadcrumbLink>
    </BreadcrumbItem>
    <BreadcrumbSeparator />
    <BreadcrumbItem>
      <BreadcrumbLink href="/components">Components</BreadcrumbLink>
    </BreadcrumbItem>
    <BreadcrumbSeparator />
    <BreadcrumbItem>
      <BreadcrumbPage>Breadcrumb</BreadcrumbPage>
    </BreadcrumbItem>
  </BreadcrumbList>
</Breadcrumb>

On this page