Stat Cards
The metric strip is a row of 4 joined stat cards separated by 1px dividers. It provides an at-a-glance summary of key metrics at the top of dashboard pages.
Anatomy
Each card contains three elements stacked vertically:
| Element | Style | Token |
|---|---|---|
| Label | Uppercase, 11px, text-2, letter-spacing 0.05em | font-sans (Plus Jakarta Sans) |
| Value | 28px, weight 800, text-1 | font-display (Lora) |
| Change indicator | 12px, weight 600, + green / - red | font-mono (JetBrains Mono) |
Usage
Used in: ho-finance (revenue, transactions, stores, margin), store-admin (sales today, items sold, average basket, returns), stock-app-web (total SKUs, low stock, incoming, outgoing).
When to use
Use stat cards for the 3--5 most important KPIs on a page. If you need more than 5, reconsider your information hierarchy.
Visual Rules
- Cards are joined in a single
bg-cardcontainer withborderdividers between them - No individual card borders or shadows --- the strip is one surface
- Consistent padding:
16px 24pxper card - Change indicators use a small arrow icon (Lucide
TrendingUp/TrendingDown) at 14px before the percentage text - Positive change:
#2D7D46(success green), Negative change:#C4463A(warm red)
HTML Demo
html
<div style="display: flex; background: #FFFFFF; border: 1px solid #E5E2DB; border-radius: 12px; overflow: hidden;">
<div style="flex: 1; padding: 16px 24px;">
<div style="font-size: 11px; text-transform: uppercase; letter-spacing: 0.05em; color: #57534E; margin-bottom: 4px;">
Penjualan Hari Ini
</div>
<div style="font-family: 'Lora', serif; font-size: 28px; font-weight: 800; color: #1A1816;">
Rp 14.230.000
</div>
<div style="font-family: 'JetBrains Mono', monospace; font-size: 12px; font-weight: 600; color: #2D7D46; margin-top: 4px;">
+12.4%
</div>
</div>
<div style="width: 1px; background: #E5E2DB;"></div>
<div style="flex: 1; padding: 16px 24px;">
<div style="font-size: 11px; text-transform: uppercase; letter-spacing: 0.05em; color: #57534E; margin-bottom: 4px;">
Transaksi
</div>
<div style="font-family: 'Lora', serif; font-size: 28px; font-weight: 800; color: #1A1816;">
247
</div>
<div style="font-family: 'JetBrains Mono', monospace; font-size: 12px; font-weight: 600; color: #C4463A; margin-top: 4px;">
-3.1%
</div>
</div>
<div style="width: 1px; background: #E5E2DB;"></div>
<!-- Repeat for remaining cards -->
</div>React Component
tsx
interface StatCard {
label: string
value: string
change?: { value: number; suffix?: string }
}
interface StatStripProps {
cards: StatCard[]
}
export function StatStrip({ cards }: StatStripProps) {
return (
<div className="flex bg-card border border-border rounded-xl overflow-hidden">
{cards.map((card, i) => (
<Fragment key={card.label}>
{i > 0 && <div className="w-px bg-border" />}
<div className="flex-1 px-6 py-4">
<p className="text-[11px] uppercase tracking-wider text-2 mb-1">
{card.label}
</p>
<p className="font-display text-[28px] font-extrabold text-1">
{card.value}
</p>
{card.change && (
<p
className={cn(
'font-mono text-xs font-semibold mt-1',
card.change.value >= 0 ? 'text-success' : 'text-danger'
)}
>
{card.change.value >= 0 ? '+' : ''}
{card.change.value}
{card.change.suffix ?? '%'}
</p>
)}
</div>
</Fragment>
))}
</div>
)
}Responsive Behavior
| Breakpoint | Behavior |
|---|---|
| Desktop (>1024px) | 4 cards in a row |
| Tablet (768--1024px) | 2x2 grid |
| Mobile (<768px) | Horizontal scroll or 2x2 stack |
Don't
- Don't use more than 5 stat cards in a single strip
- Don't mix stat cards with action buttons in the same strip
- Don't use colored backgrounds on individual cards