# V breadcrumb 12

> Checkout step progress breadcrumb with numbered circles and navigation buttons

A shadcn/ui block from the [@cnippet](https://ui.cnippet.dev/) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/cnippet/v-breadcrumb-12).

- Page, with a live preview: https://shadcn.exchange/r/cnippet/v-breadcrumb-12
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/cnippet/v-breadcrumb-12-light-3fffdc17b12eaf5f.png
- Registry item: https://ui.cnippet.dev/r/v-breadcrumb-12.json
- Categories: breadcrumb
- Listed: 2026-10-13, source last changed 2026-10-13

## Install

```bash
npx shadcn@latest add https://ui.cnippet.dev/r/v-breadcrumb-12.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Dependencies

- Registry items: `@cnippet/breadcrumb`

## Files

### `registry/default/variants/v-breadcrumb-12.tsx`

```tsx
"use client";

import { CheckIcon } from "lucide-react";
import { Fragment, useState } from "react";
import {
  Breadcrumb,
  BreadcrumbItem,
  BreadcrumbList,
  BreadcrumbPage,
  BreadcrumbSeparator,
} from "@/registry/default/ui/breadcrumb";
import { Button } from "@/registry/default/ui/button";

const steps = [
  { id: 1, label: "Cart" },
  { id: 2, label: "Shipping" },
  { id: 3, label: "Payment" },
  { id: 4, label: "Review" },
];

export function Pattern() {
  const [current, setCurrent] = useState(2);

  return (
    <div className="flex flex-col items-center gap-6">
      <Breadcrumb>
        <BreadcrumbList className="gap-1 sm:gap-1">
          {steps.map((step, i) => {
            const done = step.id < current;
            const active = step.id === current;
            return (
              <Fragment key={step.id}>
                <BreadcrumbItem>
                  {active ? (
                    <BreadcrumbPage className="flex items-center gap-1.5">
                      <span className="flex size-5 items-center justify-center rounded-full bg-primary font-bold text-[10px] text-primary-foreground">
                        {step.id}
                      </span>
                      <span className="font-semibold text-sm">
                        {step.label}
                      </span>
                    </BreadcrumbPage>
                  ) : (
                    <button
                      className={`flex items-center gap-1.5 text-sm ${done ? "text-foreground" : "text-muted-foreground/50"}`}
                      disabled={!done}
                      onClick={() => done && setCurrent(step.id)}
                      type="button"
                    >
                      <span
                        className={`flex size-5 items-center justify-center rounded-full font-bold text-[10px] ${
                          done
                            ? "bg-emerald-500 text-white"
                            : "border text-muted-foreground/50"
                        }`}
                      >
                        {done ? <CheckIcon className="size-3" /> : step.id}
                      </span>
                      {step.label}
                    </button>
                  )}
                </BreadcrumbItem>
                {i < steps.length - 1 && <BreadcrumbSeparator />}
              </Fragment>
            );
          })}
        </BreadcrumbList>
      </Breadcrumb>
      <div className="flex gap-2">
        <Button
          disabled={current === 1}
          onClick={() => setCurrent((c) => Math.max(1, c - 1))}
          size="sm"
          variant="outline"
        >
          Back
        </Button>
        <Button
          disabled={current === steps.length}
          onClick={() => setCurrent((c) => Math.min(steps.length, c + 1))}
          size="sm"
        >
          {current === steps.length - 1 ? "Place Order" : "Continue"}
        </Button>
      </div>
    </div>
  );
}
```
