One density per page

Pick comfortable or compact per page, and one quiet icon size.

From shadcn (Vercel plugin): one density system, quiet icons, Geist Mono.

One dashboard, two spacings

Show guides, reshuffle left, switch density right.

Arbitrary per cardBad
One densityGood
const DENSITY = {
  comfortable: { gap: "gap-6", pad: "p-6", text: "text-sm" },
  compact:     { gap: "gap-4", pad: "p-4", text: "text-sm" },
} as const;
const d = DENSITY.comfortable;

<main className={cn("grid", d.gap, d.pad, d.text)}>
  <section className={cn("grid grid-cols-2", d.gap)}>
    <Card className={d.pad}>…</Card>
    <Card className={d.pad}>…</Card>
  </section>
</main>

Icon sizes in a toolbar

Reshuffle the left; pick 16 or 20px on the right.

Whatever looked rightBad
One sizeGood
import { Search, Filter, Bell, Download } from "lucide-react";

<Button variant="ghost" size="icon" aria-label="Search">
  <Search className="h-4 w-4" />
</Button>

Mono for metrics and IDs

Type an amount; it lands in both tables.

UI font everywhereBad
InvoiceTimeAmount
font-sans
Mono for figuresGood
InvoiceTimeAmount
font-mono tabular-nums text-right
<TableCell className="font-mono">{invoice.number}</TableCell>
<TableCell className="font-mono text-muted-foreground">{time}</TableCell>
<TableCell className="text-right font-mono tabular-nums">
  {formatCurrency(invoice.amount)}
</TableCell>

Why it matters, pros and cons

Why it matters

One spacing value lines up edges; almost-aligned reads as a mistake.

Pros

  • Two numbers instead of one per component.
  • Comfortable to compact is one token change.
  • One icon size keeps stroke weight constant.

Cons

  • Inner gaps (label to value) use a smaller scale.
  • Dense tables may need rows tighter than p-4.
  • Marketing pages want a looser rhythm than product UI.