# Monthly Proposal Goal

> A goal progress KPI card with green segments and a configurable target.

A shadcn/ui block from the [@studio-blocks](https://studio-blocks.arhamkhnz.com/?utm_source=shadcn.exchange) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/studio-blocks/kpi-07).

- Page, with a live preview: https://shadcn.exchange/r/studio-blocks/kpi-07
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/studio-blocks/kpi-07-light-ceef71ade47e6031.png
- Registry item: https://studio-blocks.arhamkhnz.com/r/kpi-07.json
- Categories: kpi
- Listed: 2026-10-24, source last changed 2026-10-24

## Install

```bash
npx shadcn@latest add https://shadcn.exchange/r/studio-blocks/kpi-07.json
```

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

## Dependencies

- npm packages: `cn`
- Registry items: `card`

## Files

### `src/registry/blocks/kpi/kpi-07/kpi-07.tsx`

```tsx
import type { ComponentProps } from "react";
import { cn } from "cn";

import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";

export type Kpi07Props = ComponentProps<typeof Card> & {
  title?: string;
  value?: number;
  target?: number;
  unit?: string;
  period?: string;
};

export function Kpi07({
  title = "Monthly Proposal Goal",
  value = 12,
  target = 18,
  unit = "sent",
  period = "this month's",
  ...props
}: Kpi07Props) {
  const current = Number.isFinite(value) ? Math.max(0, Math.floor(value)) : 0;
  const goal = Number.isFinite(target) ? Math.max(0, Math.floor(target)) : 0;
  const progress = goal > 0 ? Math.min(1, current / goal) : 0;
  const percentage = Math.round(progress * 100);
  const segments = 42;
  const activeSegments = Math.round(progress * segments);
  const format = (number: number) => number.toLocaleString("en-US");

  return (
    <Card {...props}>
      <CardHeader>
        <CardTitle className="font-normal">{title}</CardTitle>
      </CardHeader>
      <CardContent className="flex flex-col gap-2">
        <div className="flex flex-wrap items-baseline justify-between gap-3">
          <div className="flex items-baseline gap-1.5">
            <span className="text-3xl leading-none tracking-tight tabular-nums">{format(current)}</span>
            <span className="text-base text-muted-foreground">{unit}</span>
          </div>
          <span className="text-sm text-muted-foreground tabular-nums">{format(goal)} target</span>
        </div>
        <div
          role="progressbar"
          aria-label={title}
          aria-valuemin={0}
          aria-valuemax={100}
          aria-valuenow={percentage}
          aria-valuetext={`${format(current)} of ${format(goal)} target reached`}
          className="flex h-8 gap-0.5"
        >
          {Array.from({ length: segments }, (_, index) => (
            <span
              key={index}
              aria-hidden="true"
              className={cn("min-w-0 flex-1 rounded-full", index < activeSegments ? "bg-green-500" : "bg-green-500/15")}
            />
          ))}
        </div>
        <p className="text-xs text-muted-foreground">
          {goal > 0 ? `${percentage}% of ${period} target reached.` : "Set a target to track your progress."}
        </p>
      </CardContent>
    </Card>
  );
}
```
