# V progress 9

> Monthly Budget Breakdown

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

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

## Install

```bash
npx shadcn@latest add https://ui.cnippet.dev/r/v-progress-9.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/progress`

## Files

### `registry/default/variants/v-progress-9.tsx`

```tsx
import {
  Card,
  CardDescription,
  CardHeader,
  CardPanel,
  CardTitle,
} from "@/registry/default/ui/card";
import {
  Progress,
  ProgressIndicator,
  ProgressTrack,
} from "@/registry/default/ui/progress";

const categories = [
  {
    budget: 600,
    color: "**:data-[slot=progress-indicator]:bg-blue-500",
    label: "Housing",
    spent: 600,
  },
  {
    budget: 400,
    color: "**:data-[slot=progress-indicator]:bg-emerald-500",
    label: "Groceries",
    spent: 284,
  },
  {
    budget: 150,
    color: "**:data-[slot=progress-indicator]:bg-violet-500",
    label: "Transport",
    spent: 137,
  },
  {
    budget: 200,
    color: "**:data-[slot=progress-indicator]:bg-amber-500",
    label: "Dining out",
    spent: 198,
  },
  {
    budget: 100,
    color: "**:data-[slot=progress-indicator]:bg-rose-500",
    label: "Entertainment",
    spent: 121,
  },
  {
    budget: 80,
    color: "**:data-[slot=progress-indicator]:bg-cyan-500",
    label: "Health",
    spent: 42,
  },
];

const totalBudget = categories.reduce((s, c) => s + c.budget, 0);
const totalSpent = categories.reduce((s, c) => s + c.spent, 0);
const remaining = totalBudget - totalSpent;

export function Pattern() {
  return (
    <div className="w-full max-w-sm">
      <Card>
        <CardHeader className="border-b">
          <CardTitle>May Budget</CardTitle>
          <CardDescription>
            <span
              className={remaining < 0 ? "font-medium text-destructive" : ""}
            >
              ${Math.abs(remaining).toFixed(0)}{" "}
              {remaining < 0 ? "over budget" : "remaining"}
            </span>
            {" · "}${totalSpent} of ${totalBudget} spent
          </CardDescription>
        </CardHeader>
        <CardPanel className="space-y-4">
          {categories.map((cat) => {
            const _pct = Math.min((cat.spent / cat.budget) * 100, 100);
            const over = cat.spent > cat.budget;
            return (
              <Progress
                className={cat.color}
                key={cat.label}
                max={cat.budget}
                value={cat.spent}
              >
                <div className="flex items-center justify-between text-xs">
                  <span className="font-medium">{cat.label}</span>
                  <span
                    className={`tabular-nums ${over ? "font-medium text-destructive" : "text-muted-foreground"}`}
                  >
                    ${cat.spent}
                    <span className="font-normal text-muted-foreground">
                      {" "}
                      / ${cat.budget}
                    </span>
                  </span>
                </div>
                <ProgressTrack className="h-2">
                  <ProgressIndicator
                    className={over ? "bg-destructive!" : undefined}
                  />
                </ProgressTrack>
                {over && (
                  <p className="text-destructive text-xs">
                    ${cat.spent - cat.budget} over limit
                  </p>
                )}
              </Progress>
            );
          })}
        </CardPanel>
      </Card>
    </div>
  );
}
```
