# Stat cards

> A responsive grid of KPI cards, each showing a value with a delta badge versus last month.

A shadcn/ui block from the [@quill](https://www.quilldesignsystem.com) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/quill/stat-cards).

- Page, with a live preview: https://shadcn.exchange/r/quill/stat-cards
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/quill/stat-cards-light-dadb9eb66f9364a6.png
- Registry item: https://www.quilldesignsystem.com/r/stat-cards.json
- Categories: data-display
- Listed: 2026-10-13, source last changed 2026-10-13

## Install

```bash
npx shadcn@latest add https://www.quilldesignsystem.com/r/stat-cards.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: `card`, `badge`

## Notes from the registry

A responsive grid of KPI cards, each showing a value with a delta badge versus last month. Do: Match badge tone to whether the delta is actually good news for that metric (e.g. rising churn is bad, so it gets destructive tone even though the number itself looks like growth). Don't: Default every rising number to a positive tone — a rising "Open tickets" count is bad news, not good. Use analytics-charts when you need to show the trend shape over time, not just the current value and one delta. Use data-table when you have more metrics than fit comfortably in a card grid, or need to compare many rows at once.

## Files

### `registry/blocks/stat-cards.tsx`

```tsx
import {
  Card,
  CardHeader,
  CardTitle,
  CardDescription,
  CardContent,
} from '@/components/ui/card'
import { Badge } from '@/components/ui/badge'

const stats = [
  { label: 'Total revenue', value: '$48,120', delta: '+12.4%', tone: 'default' as const },
  { label: 'Active users', value: '3,842', delta: '+4.1%', tone: 'default' as const },
  { label: 'Churn', value: '1.9%', delta: '−0.3%', tone: 'secondary' as const },
  { label: 'Open tickets', value: '27', delta: '+6', tone: 'destructive' as const },
]

/** A responsive grid of KPI cards, each showing a value with a delta badge versus last month. */
export function StatCards() {
  return (
    <div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4">
      {stats.map((s) => (
        <Card key={s.label}>
          <CardHeader>
            <CardDescription>{s.label}</CardDescription>
            <CardTitle className="text-2xl">{s.value}</CardTitle>
          </CardHeader>
          <CardContent>
            <Badge variant={s.tone}>{s.delta}</Badge>
            <span className="ml-2 text-sm text-muted-foreground">vs last month</span>
          </CardContent>
        </Card>
      ))}
    </div>
  )
}
```
