Dashboards

Cards and statistics

A number, its label, its period and its direction. Getting the fourth wrong is how a dashboard lies politely.

A stat card is four things

the shape
<Card>
  <p className="text-sm text-muted-foreground">Active customers</p>
  <p className="mt-2 text-3xl font-semibold tabular-nums">1,284</p>
  <p className="mt-1 text-sm">
    <span className="text-success">+12.4%</span>{" "}
    <span className="text-muted-foreground">vs Last Month</span>
  </p>
</Card>
  • The label, muted, above the number rather than below it.
  • The number, large, with tabular-nums so a row of cards does not jitter as figures change width.
  • The delta, with its sign.
  • The period. Without it, the delta is decoration.

Up is not always good

Colouring every rise green is the most common mistake on a dashboard, and it is a lie on every metric where less is better: churn, refunds, error rate, time to first response, cost per acquisition. Take the direction from the meaning, not the sign.

direction, not sign
// "better" is a property of the metric, not of the number.
const tone = (delta: number, better: "up" | "down") =>
  delta === 0
    ? "text-muted-foreground"
    : (delta > 0) === (better === "up")
      ? "text-success"
      : "text-destructive";

⚠️ Colour is not the only signal

Roughly one man in twelve cannot reliably separate your success green from your destructive red. Keep the arrow and the sign, so the direction survives without the colour.

Use the tokens

--success, --warning, --info and --destructive are the whole state family, in light and dark. Reaching past them to text-emerald-500 is how a themed product ends up with one colour a buyer cannot change.