Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

KPI Card Variations

snoo edited this page Apr 7, 2026 · 1 revision

KPI Card Variations

A 2x2 KPI grid is a staple of dashboard design. This guide shows how to make the 4 cards feel distinct and purposeful rather than repetitive.


The Standard StatCard

<StatCard
 icon={CreditCard}
 label="TODAY'S REVENUE"
 value="1,870"
 unit="K"
 trend={{ value: "+8.2%", direction: "up" }}
/>

Internal structure:

┌──────────────────────────┐
│ [icon badge] LABEL │ ← 12px uppercase tracking-wide
│ │
│ 1,870K │ ← 36px bold + 18px unit (2:1)
│ │
│ +8.2% ↑ │ ← 13px bold, text-success
└──────────────────────────┘

6 Variation Strategies

1. Vary the Icons

Each card should have a unique, semantically meaningful icon. This breaks the visual silhouette:

Metric Icon Why
Revenue Wallet or DollarSign Money container
Orders Package Physical goods
Visitors Users People
Conversion Target Goal/aim
Churn UserMinus User leaving
Growth TrendingUp Direction

2. Vary the Units

Different units create different text rhythm within the 2:1 ratio:

{/* Short unit -- feels compact */}
<StatCard value="3.8" unit="M" />
{/* Medium unit -- balanced */}
<StatCard value="1,870" unit="USD" />
{/* Percentage -- minimal */}
<StatCard value="12.4" unit="%" />
{/* No unit -- just a count */}
<StatCard value="247" />

3. Mix Trend Directions

When all 4 trends point up, the grid looks artificially positive. Real data naturally mixes:

<div className="grid grid-cols-2 gap-4 px-6">
 <StatCard label="REVENUE" trend={{ value: "+14.2%", direction: "up" }} ... />
 <StatCard label="CHURN RATE" trend={{ value: "-0.4%", direction: "down" }} ... />
 <StatCard label="ARPU" trend={{ value: "+1.8%", direction: "up" }} ... />
 <StatCard label="SUPPORT" trend={{ value: "+12", direction: "up" }} ... />
</div>

A "down" trend uses text-destructive and TrendingDown, naturally creating color contrast.

4. Vary Number Magnitude

Different scales of numbers prevent the grid from feeling uniform:

Card Value Visual Texture
Card 1 3.8M Short, with decimal
Card 2 1,870 Medium, with comma
Card 3 247 Short integer
Card 4 12.4% Decimal percentage

5. Add a Progress Bar to One Card

One card in the grid can include a progress bar below the metric, making it visually taller and heavier:

<div className="bg-card rounded-2xl p-6 shadow-[var(--shadow-card)]">
 <div className="flex items-center gap-2 mb-3">
 <div className="size-7 rounded-lg bg-brand/10 flex items-center justify-center">
 <Target className="size-4 text-brand" />
 </div>
 <p className="text-[12px] text-text-secondary font-medium uppercase tracking-[0.05em]">
 GOAL PROGRESS
 </p>
 </div>
 <p className="text-text-primary text-[36px] font-bold leading-none whitespace-nowrap">
 68<span className="text-[18px] ms-0.5">%</span>
 </p>
 {/* Progress bar adds visual weight */}
 <div className="mt-3 bg-surface-muted rounded-full h-4 overflow-hidden">
 <div className="bg-brand h-full w-[68%] rounded-full" />
 </div>
</div>

6. Use a Segment Bar for Discrete Progress

For discrete metrics (8 out of 10 tasks done), use the segment bar instead of continuous progress:

<div className="mt-3 flex gap-1">
 {[...Array(10)].map((_, i) => (
 <div key={i} className={`h-6 flex-1 rounded ${i < 8 ? 'bg-brand' : 'bg-surface-muted'}`} />
 ))}
</div>

Grid Layout Options

Standard 2x2

<div className="grid grid-cols-2 gap-4 px-6">
 {/* 4 cards */}
</div>

1 + 2 (featured metric + supporting)

<div className="space-y-4 px-6">
 {/* Full-width stat card with progress bar */}
 <StatCard className="col-span-2" ... />
 <div className="grid grid-cols-2 gap-4">
 <StatCard ... />
 <StatCard ... />
 </div>
</div>

3-Column (for smaller metrics)

For information-dense dashboards with 6 mini metrics:

<div className="grid grid-cols-3 gap-3 px-6">
 {/* 3 or 6 compact cards */}
</div>

Color Rules in KPI Grids

Element Color Rule
Icon badge background bg-brand/10 Always 10% opacity of accent
Icon text-brand Always accent color
Value text text-text-primary (#3C3C3C) Never accent color
Up trend text-success (#6B9B7A) Calm green, not vivid
Down trend text-destructive (#D4183D) Only for negative values
Label text-text-secondary (#6A6A6A) Always secondary gray
Unit text-text-primary at smaller size Same color as value, smaller

Common Mistakes

Mistake Fix
All 4 cards use the same icon Use semantically distinct icons
Trend shows "+0.0%" Hide trend icon when value is zero; show "0%" in gray
Giant numbers overflow the card Scale unit up: 18,700,000 -> 1,870K
Adding borders to individual grid cards Cards use shadow only, no borders (light mode)
Making one card a different background color All cards are bg-card (white), no exceptions

Clone this wiki locally

AltStyle によって変換されたページ (->オリジナル) /