MetricGrid
Smart auto-layout grid for dashboards. Drop components in, it figures out the layout from component types.
import { MetricGrid } from "metricui";When to Use
Use MetricGrid as the auto-layout container for dashboards. Drop MetricUI components in and it figures out the layout — KPI cards go in equal-width rows, charts split side-by-side, tables go full width. No Tailwind grid classes, no manual column math, no responsive breakpoints to manage. Override individual items with MetricGrid.Item when the auto-layout is not what you want.
Basic Example
A typical dashboard with KPI cards, charts, and a table. MetricGrid detects each component type and assigns the right width automatically.
| Page | Views | Bounce Rate |
|---|---|---|
| /pricing | 12.8K | 32% |
| /docs | 9.4K | 18% |
| /blog/launch | 7.2K | 45% |
| /signup | 5.8K | 12% |
<MetricGrid>
<KpiCard title="Revenue" value={78400} format="currency" comparison={{ value: 65200 }} />
<KpiCard title="Users" value={3200} format="number" comparison={{ value: 2800 }} />
<KpiCard title="Conversion" value={4.2} format="percent" comparison={{ value: 3.8 }} />
<AreaChart
data={revenueData}
index="date"
categories={["revenue", "cost"]}
title="Revenue vs Cost"
format="currency"
/>
<BarChart
data={channelData}
index="channel"
categories={["visits"]}
title="Traffic by Channel"
/>
<DataTable data={tableData} columns={columns} title="Top Pages" />
</MetricGrid>MetricGrid.Section
MetricGrid.Section renders a full-width labeled divider between groups of components. It delegates to SectionHeader internally, so it supports all the same props: subtitle, description, action, badge, and border.
Overview
Key metrics at a glance
Trends
Details
| Page | Views | Bounce Rate |
|---|---|---|
| /pricing | 12.8K | 32% |
| /docs | 9.4K | 18% |
| /blog/launch | 7.2K | 45% |
| /signup | 5.8K | 12% |
<MetricGrid>
<MetricGrid.Section title="Overview" subtitle="Key metrics at a glance" />
<KpiCard title="Revenue" value={78400} format="currency" />
<KpiCard title="Users" value={3200} />
<KpiCard title="Conversion" value={4.2} format="percent" />
<MetricGrid.Section title="Trends" border />
<AreaChart data={revenueData} index="date" categories={["revenue"]} title="Revenue Over Time" />
<MetricGrid.Section title="Details" border />
<DataTable data={tableData} columns={columns} title="Top Pages" />
</MetricGrid>MetricGrid.Item
Wrap any child in MetricGrid.Item to override the auto-detected width. The span prop accepts "sm", "md", "lg", "full", or a number from 1 to 12.
<MetricGrid>
<KpiCard title="Revenue" value={78400} format="currency" />
<KpiCard title="Users" value={3200} />
{/* Force this chart to full width instead of auto-pairing */}
<MetricGrid.Item span="full">
<AreaChart data={data} title="Revenue Over Time" />
</MetricGrid.Item>
<DataTable data={tableData} title="Details" />
</MetricGrid>| Span | Behavior |
|---|---|
"sm" | 1/4 width |
"md" | 1/3 width |
"lg" | 2/3 width |
"full" | Full width |
1-12 | Explicit column count out of 12 |
Auto-Detection
MetricGrid inspects each child's component type to decide how to lay it out. It checks for a static __gridHint property first, then falls back to matching the component's displayName. Unknown component types default to full width, so custom components are never broken.
| Component | Grid Hint | Layout Behavior |
|---|---|---|
KpiCard | kpi | Equal-width row with other KPIs (up to 4 per row) |
Gauge | gauge | Equal-width row with other small items |
StatGroup | stat | Full width |
AreaChart, LineChart, BarChart, ... | chart | Two charts: 2:1 split. Three: equal thirds. Single: full width |
DataTable | table | Full width |
DashboardHeader | header | Full width |
MetricGrid.Section | full | Full width (labeled divider) |
Unknown / custom | unknown | Full width (safe default) |
To make your own custom component auto-detected, set the static __gridHint property:
import type { GridHint } from "metricui";
function MyCustomChart(props) {
return <div>...</div>;
}
MyCustomChart.__gridHint = "chart" as GridHint;
// Now MetricGrid will treat it like any other chartProps
| Prop | Type | Default | Description |
|---|---|---|---|
children* | React.ReactNode | — | MetricUI components. Layout is auto-detected from component types. |
columns | number | 4 | Max small items (KPIs, Gauges) per row. |
gap | number | 16 | Gap between items in px. Dense mode uses 12. |
className | string | — | Additional class names. |
id | string | — | HTML id. |
data-testid | string | — | Test id. |
MetricGrid.Section Props
| Prop | Type | Default | Description |
|---|---|---|---|
title | string | (required) | Section label. |
subtitle | string | — | Secondary label below the title. |
description | string | ReactNode | — | Content for the info popover. |
action | ReactNode | — | Right-aligned action slot. |
badge | ReactNode | — | Inline badge after the title. |
border | boolean | false | Show a border line above the section. |
className | string | — | Additional CSS classes. |
MetricGrid.Item Props
| Prop | Type | Default | Description |
|---|---|---|---|
span | "sm" | "md" | "lg" | "full" | number | — | Override the auto-detected column width. |
children | ReactNode | (required) | The component to render. |
className | string | — | Additional CSS classes. |
Notes
- Auto-layout rules: consecutive KPIs → equal-width row, two charts → 2:1 split, single chart → full width, table → full width.
- Items in the same row always fill the space evenly. 3 KPIs = thirds, not 3 + gap.
- Unknown component types default to full width — no lock-in.
- MetricGrid.Section renders a full-width labeled divider with the same muted uppercase style.
- MetricGrid.Item accepts span='sm'|'md'|'lg'|'full' or a column count number.
- Responsive: 4 cols at lg, 2 at sm, 1 below 640px.
- Reveal-on-scroll: each grid cell animates in with a staggered 60ms fade+slide. Respects animate={false} and prefers-reduced-motion.