Cookbook
Recipes for every “I didn't know you could do that” moment. Each recipe is live — what you see is what you get.
Tables That Do Everything
DataTable columns have a type field that transforms plain data into rich UI. No render functions needed.
Sparklines in cells
| Metric | 7-Day Trend |
|---|---|
| Revenue | |
| Users |
<DataTable
data={[
{ name: "Revenue", trend: [12, 18, 14, 22, 19, 26, 31] },
{ name: "Users", trend: [80, 85, 78, 92, 95, 88, 102] },
]}
columns={[
{ key: "name", header: "Metric" },
{ key: "trend", header: "7-Day Trend", type: "sparkline" },
]}
/>Status dots in cells
| Service | Health |
|---|---|
| API | Healthy |
| Database | Degraded |
| CDN | Down |
<DataTable
data={[
{ service: "API", uptime: 99.98 },
{ service: "Database", uptime: 97.2 },
{ service: "CDN", uptime: 89.1 },
]}
columns={[
{ key: "service", header: "Service" },
{ key: "uptime", header: "Health", type: "status",
statusRules: [
{ min: 99.9, color: "emerald", label: "Healthy" },
{ min: 95, color: "amber", label: "Degraded", pulse: true },
{ color: "red", label: "Down", pulse: true },
],
},
]}
dense
/>Inline bar fills
| Server | CPU Usage |
|---|---|
| Acme Corp | 92% |
| Globex | 67% |
| Initech | 34% |
| Umbrella | 88% |
| Cyberdyne | 12% |
{ key: "usage", header: "CPU", type: "bar", format: "percent",
conditions: [
{ when: "at_or_above", value: 90, color: "red" },
{ when: "at_or_above", value: 70, color: "amber" },
{ when: "below", value: 70, color: "emerald" },
]
}Expandable detail rows
Click the chevron to expand a row and reveal nested components — charts, stats, anything.
| Customer | Revenue | Status | |
|---|---|---|---|
| Acme Corp | $84.2K | active | |
| Globex | $62.1K | active | |
| Initech | $31.4K | trial |
<DataTable
data={customers}
columns={columns}
renderExpanded={(row) => (
<div className="grid grid-cols-3 gap-3">
<KpiCard bare title="Revenue" value={row.revenue} format="currency" />
<KpiCard bare title="Completion" value={row.completion} format="percent" />
<Sparkline data={row.trend} height={48} />
</div>
)}
/>Hierarchical rows
| Region | Revenue | |
|---|---|---|
| North America | $1.2M | |
| US East | $450.0K | |
| US West | $380.0K | |
| Canada | $370.0K | |
| Europe | $800.0K | |
| UK | $350.0K | |
| Germany | $280.0K | |
| France | $170.0K |
<DataTable
data={[
{ region: "North America", revenue: 1200000, children: [
{ region: "US East", revenue: 450000 },
{ region: "US West", revenue: 380000 },
{ region: "Canada", revenue: 370000 },
]},
]}
childrenField="children"
defaultExpanded
/>Row highlighting
| Account | Revenue | Churn | Growth |
|---|---|---|---|
| Acme Corp | $84.2K | 0% | 0% |
| Globex | $62.1K | 0% | 0% |
| Initech | $31.4K | 0% | -0% |
| Umbrella | $95.6K | 0% | 0% |
| Cyberdyne | $18.9K | 0% | -0% |
<DataTable
data={accounts}
rowConditions={[
{ when: (row) => row.churn > 0.15, className: "bg-red-500/5" },
{ when: (row) => row.growth > 0.30, className: "bg-emerald-500/5" },
]}
/>KPI Cards Beyond Basics
These recipes show what most devs discover weeks into using MetricUI.
Multiple comparisons
<KpiCard
title="Revenue"
value={127450}
format="currency"
comparison={[
{ value: 113500, label: "vs last month" },
{ value: 98200, label: "vs last year", mode: "absolute" },
]}
/>Down is good
<KpiCard
title="Churn Rate"
value={3.2}
format="percent"
icon={<TrendingDown className="h-3.5 w-3.5" />}
comparison={{ value: 4.8, invertTrend: true }}
/>Goal tracking
<KpiCard
title="Q2 Revenue"
value={380000}
format="currency"
icon={<DollarSign className="h-3.5 w-3.5" />}
goal={{
value: 500000,
label: "Q2 Target",
showTarget: true,
showRemaining: true,
color: "#6366F1",
completeColor: "#10B981",
}}
/>Previous period sparkline
<KpiCard
title="Daily Revenue"
value={12400}
format="currency"
sparkline={{
data: thisWeek,
previousPeriod: lastWeek,
type: "bar",
}}
/>Conditional glow
The card gets a colored glow when the value hits a threshold.
<KpiCard
title="Error Rate"
value={12.4}
format="percent"
conditions={[
{ when: "at_or_above", value: 10, color: "red" },
{ when: "at_or_above", value: 5, color: "amber" },
{ when: "below", value: 5, color: "emerald" },
]}
/>Charts That Tell Stories
Overlay targets, thresholds, and dual axes to turn a chart into a narrative.
Target lines
<AreaChart
data={data}
index="month"
categories={["revenue"]}
format="currency"
referenceLines={[
{ axis: "y", value: 70000, label: "Target", color: "#6366F1", style: "dashed" },
{ axis: "y", value: 50000, label: "Break-even", color: "#EF4444" },
]}
enableArea gradient
/>Threshold zones
<AreaChart
data={data}
index="month"
categories={["orders"]}
thresholds={[
{ from: 0, to: 350, color: "#EF4444", opacity: 0.06, label: "Low" },
{ from: 350, to: 450, color: "#F59E0B", opacity: 0.06, label: "Normal" },
{ from: 450, to: 600, color: "#10B981", opacity: 0.06, label: "High" },
]}
/>Dual Y-axis
<AreaChart
data={data}
index="month"
categories={[
{ key: "revenue", format: "currency" },
{ key: "orders", format: "number", axis: "right" },
]}
rightAxisLabel="Orders"
enableArea gradient
/>100% stacked
<AreaChart
data={channelData}
index="month"
categories={["organic", "paid", "referral", "direct"]}
stacked
stackMode="percent"
format="percent"
title="Traffic Mix"
/>Per-series styling
<AreaChart
data={data}
index="month"
categories={["revenue", "costs"]}
format="currency"
seriesStyles={{
revenue: { lineWidth: 2.5 },
costs: { lineStyle: "dashed", lineWidth: 1.5 },
}}
/>Target vs actual bars
<BarChart
data={actuals}
index="rep"
categories={["closed"]}
targetData={targets}
title="Deals Closed vs Target"
/>Layout Without CSS
Drop components into MetricGrid. KPIs row up, charts split intelligently, tables go full-width. No grid classes.
Trends
<MetricGrid>
<KpiCard title="Revenue" value={127450} format="currency" />
<KpiCard title="Users" value={8420} format="number" />
<KpiCard title="Conversion" value={4.8} format="percent" />
<MetricGrid.Section title="Trends" />
<AreaChart data={data} index="month" categories={["revenue"]} />
<DonutChart data={plans} index="plan" categories={["users"]} />
</MetricGrid>Data-Driven Alerts
Callout evaluates rules against a value and picks the variant automatically.
Critical: 12.4% error rate
<Callout
value={12.4}
rules={[
{ min: 10, variant: "error",
title: "Critical: {value}% error rate",
message: "Immediate action required." },
{ min: 5, variant: "warning",
title: "Elevated: {value}% error rate" },
{ variant: "success",
title: "Error rate normal" },
]}
metric={{ value: 12.4, format: "percent", label: "current" }}
dismissible dense
/>Live Ops Patterns
StatusIndicator at size="card" matches KpiCard and slots into MetricGrid.
Healthy
Degraded
Healthy
<MetricGrid columns={3}>
<StatusIndicator
size="card"
title="API Gateway"
value={99.97}
rules={[
{ min: 99.9, color: "emerald", label: "Healthy" },
{ min: 95, color: "amber", label: "Degraded", pulse: true },
{ color: "red", label: "Down", pulse: true },
]}
since={new Date(Date.now() - 3600000 * 4)}
trend={[99.1, 99.5, 99.8, 99.9, 99.97]}
/>
<StatusIndicator size="card" title="Database" value={98.2}
rules={[
{ min: 99.9, color: "emerald", label: "Healthy" },
{ min: 95, color: "amber", label: "Degraded", pulse: true },
{ color: "red", label: "Down", pulse: true },
]}
/>
<StatusIndicator size="card" title="CDN" value={99.99}
rules={[
{ min: 99.9, color: "emerald", label: "Healthy" },
{ min: 95, color: "amber", label: "Degraded", pulse: true },
{ color: "red", label: "Down", pulse: true },
]}
/>
</MetricGrid>Feature Enablement Matrix
Use DataTable with custom render functions to build feature comparison matrices — plans vs features, customers vs capabilities, any two-dimensional mapping.
| Feature | Starter | Pro | Enterprise |
|---|---|---|---|
Dashboard Builder Drag-and-drop layout editor | |||
Custom Charts Build charts from any data source | |||
Team Sharing | |||
API Access REST & GraphQL endpoints | |||
SSO / SAML | |||
Audit Log | Limited | ||
Custom Branding | |||
SLA Uptime guarantee | Limited | ||
Dedicated Support |
<DataTable
data={features}
columns={[
{ key: "feature", header: "Feature", pin: "left",
render: (v, row) => (
<div>
<span className="font-medium">{v}</span>
{row.description && (
<p className="text-xs text-[var(--muted)]">{row.description}</p>
)}
</div>
),
},
...["Starter", "Pro", "Enterprise"].map((plan) => ({
key: plan.toLowerCase(),
header: plan,
align: "center",
render: (v) =>
v === true ? <Check className="text-emerald-500" /> :
v === "limited" ? <Badge color="amber" size="sm">Limited</Badge> :
<Minus className="text-[var(--muted)]" />,
})),
]}
/>SaaS tenant matrix
Internal ops pattern — a tenant-by-module rollout matrix with icon status indicators and expandable detail rows. Great for CSM dashboards, feature rollout tracking, and adoption monitoring.
12 studios · 5 modules
| Studio | Acct Mgr | Rooms | Scheduling | Billing | Retention | Reports | API | |
|---|---|---|---|---|---|---|---|---|
Iron TempleENT | Nora Voss | 38 | ||||||
CorePulse FitnessMid | Nora Voss | 12 | ||||||
Zenith YogaSMB | Leo Park | 2 | ||||||
Lift LabENT | Nora Voss | 24 | ||||||
Barre & BeyondMid | Leo Park | 6 | ||||||
SweatBoxSMB | Self Service | 1 | ||||||
Peak PerformanceENT | Nora Voss | 31 | ||||||
Cycle SocietyMid | Leo Park | 8 | ||||||
FlexPoint StudiosSMB | Self Service | 3 | ||||||
Grind AthleticsMid | Leo Park | 10 |
const renderStage = (v: unknown) => {
const s = String(v);
if (s === "R") return <CheckCircle2 className="mx-auto h-4 w-4 text-emerald-500" />;
if (s === "D") return <Loader className="mx-auto h-4 w-4 text-amber-500" />;
if (s === "S") return <Wrench className="mx-auto h-4 w-4 text-blue-500" />;
return <Minus className="mx-auto h-4 w-4 text-[var(--muted)] opacity-30" />;
};
const modules = ["Scheduling", "Billing", "Retention", "Reports", "API"];
<DataTable
title="Studio Module Rollout"
subtitle="12 studios · 5 modules"
data={studios}
columns={[
{ key: "studio", header: "Studio", pin: "left", sortable: true,
render: (v, row) => (
<div>
<span className="font-medium">{v}</span>
<span className="ml-2 text-[10px] text-[var(--muted)]">{row.tier}</span>
</div>
),
},
{ key: "am", header: "Acct Mgr", sortable: true },
{ key: "rooms", header: "Rooms", type: "number", sortable: true, width: 70 },
...modules.map((m) => ({
key: m.toLowerCase(), header: m, align: "center", width: 90,
render: renderStage,
})),
]}
footnote={
<div className="flex flex-wrap gap-x-5 gap-y-1">
<span className="flex items-center gap-1"><CheckCircle2 className="h-3 w-3 text-emerald-500" /> Live</span>
<span className="flex items-center gap-1"><Loader className="h-3 w-3 text-amber-500" /> In progress</span>
<span className="flex items-center gap-1"><Wrench className="h-3 w-3 text-blue-500" /> Setting up</span>
<span className="flex items-center gap-1"><Minus className="h-3 w-3 opacity-30" /> Not enabled</span>
</div>
}
renderExpanded={(row) => ( /* customer detail grid */ )}
searchable
dense
maxRows={10}
/>The Everything Table
One table that is the dashboard. Every column type in play — sparklines, progress bars, status dots, badges, bar fills, conditional colors — plus expandable detail rows with nested KpiCards. Try doing this in Metabase.
Account health matrix
6 accounts · click any row to expand
| Account | ARR | 7d Trend | Health | Adoption | NPS | Churn Risk | Renews | |
|---|---|---|---|---|---|---|---|---|
NovaTechEnterprise | 284K | healthy | 72 | 0% | 45d | |||
BrightPathMid-Market | 126K | healthy | 61 | 0% | 120d | |||
Meridian LabsMid-Market | 89K | at-risk | 28 | 0% | 30d | |||
Apex IndustriesEnterprise | 412K | healthy | 84 | 0% | 200d | |||
Flux DigitalSMB | 34K | churning | 12 | 1% | 14d | |||
Orion GroupEnterprise | 198K | healthy | 55 | 0% | 90d |
<DataTable
title="Account Health Matrix"
subtitle="6 accounts · click any row to expand"
data={accounts}
columns={[
{ key: "account", header: "Account", pin: "left", sortable: true },
{ key: "arr", header: "ARR", type: "currency", format: "compact", sortable: true },
{ key: "trend", header: "7d Trend", type: "sparkline" },
{ key: "health", header: "Health", type: "badge" },
{ key: "adoption", header: "Adoption", type: "progress" },
{ key: "nps", header: "NPS", type: "number", sortable: true,
conditions: [
{ min: 50, color: "emerald" },
{ min: 20, color: "amber" },
{ color: "red" },
],
},
{ key: "risk", header: "Churn Risk", type: "bar", format: "percent" },
{ key: "renewsIn", header: "Renews", type: "number", sortable: true,
render: (v) => <Badge variant={v <= 30 ? "danger" : v <= 90 ? "warning" : "default"} size="sm">{v}d</Badge>,
},
]}
renderExpanded={(row) => (
<MetricGrid columns={4}>
<KpiCard title="Seats Used" value={`${row.seatsUsed}/${row.seats}`} ... />
<KpiCard title="ARR" value={row.arr} format="currency" ... />
<KpiCard title="Adoption" value={row.adoption} format="percent" ... />
<KpiCard title="NPS Score" value={row.nps} ... />
</MetricGrid>
)}
searchable
dense
/>Ops War Room
A live operations board that feels alive. Pulsing status indicators for degraded services, data-driven callouts that auto-switch severity, KPIs with conditional glow — all updating from a single data source. BI dashboards are screenshots by comparison.
System status board
System Status
LiveReal-time infrastructure health
Healthy
Degraded
Healthy
Down
Critical: systems impaired
ms
<MetricProvider theme="slate">
<MetricGrid>
<SectionHeader title="System Status" subtitle="Real-time infrastructure health" />
<StatusIndicator size="card" title="API Gateway" value={99.97} rules={[...]} since={...} trend={[...]} />
<StatusIndicator size="card" title="Database Primary" value={98.2} rules={[...]} />
<StatusIndicator size="card" title="CDN Edge" value={99.99} rules={[...]} />
<StatusIndicator size="card" title="Queue Workers" value={94.1} rules={[...]} />
<Callout value={94.1} rules={[
{ min: 99, variant: "success", title: "All systems operational" },
{ min: 95, variant: "warning", title: "Degraded: {value}% uptime" },
{ variant: "error", title: "Critical: {value}% uptime" },
]} />
<KpiCard title="P50 Latency" value={42} ... conditions={[...]} />
<KpiCard title="Error Rate" value={0.08} format="percent" ... conditions={[...]} />
<KpiCard title="Active Connections" value={12847} ... />
<KpiCard title="Queue Depth" value={342} ... conditions={[...]} />
<AreaChart title="Request Volume (24h)" data={...} thresholds={[...]} referenceLines={[...]} />
</MetricGrid>
</MetricProvider>The Metric Sandwich
Three layers, one story. KPI cards on top for the headlines, a chart in the middle for the trend, a detail table on the bottom for the drill-down — all wired together with linked hover and cross-filtering. Hover a point on the chart and the matching table row highlights. Click a table row and everything filters. Impossible in any BI tool.
Revenue deep-dive
across 525 customers
Revenue by product line
| Product | Revenue | 6m Trend | Customers | Growth | Status | |
|---|---|---|---|---|---|---|
| Pro Plan | $38.2K | 142 | 0% | active | ||
| Enterprise | $24.8K | 28 | 0% | active | ||
| Starter | $5.2K | 310 | -0% | warning | ||
| API Add-on | $2.8K | 45 | 1% | active |
<LinkedHoverProvider>
<CrossFilterProvider>
<MetricGrid>
{/* Layer 1: KPI headlines */}
<KpiCard title="Total Revenue" value={329000} format="currency" comparison={...} sparkline={...} />
<KpiCard title="Avg Deal Size" value={245} format="currency" comparison={...} />
<KpiCard title="Active Products" value={4} comparison={...} />
<KpiCard title="Net Margin" value={0.38} format="percent" goal={...} conditions={...} />
{/* Layer 2: Trend chart */}
<AreaChart title="Monthly Revenue vs Expenses" data={monthly} ... referenceLines={[...]} thresholds={[...]} />
{/* Layer 3: Detail table with everything */}
<DataTable title="Product Breakdown" data={products} columns={[...]} renderExpanded={...} />
</MetricGrid>
</CrossFilterProvider>
</LinkedHoverProvider>