M
MetricUI
UI

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.

Revenue
$0
+20.2%
Users
0
+14.3%
Conversion
0%
+10.5%
Revenue vs Cost
Traffic by Channel
Top Pages
PageViewsBounce Rate
/pricing12.8K32%
/docs9.4K18%
/blog/launch7.2K45%
/signup5.8K12%
<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

Revenue
$0
Users
0
Conversion
0%

Trends

Revenue Over Time

Details

Top Pages
PageViewsBounce Rate
/pricing12.8K32%
/docs9.4K18%
/blog/launch7.2K45%
/signup5.8K12%
<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>
SpanBehavior
"sm"1/4 width
"md"1/3 width
"lg"2/3 width
"full"Full width
1-12Explicit 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.

ComponentGrid HintLayout Behavior
KpiCardkpiEqual-width row with other KPIs (up to 4 per row)
GaugegaugeEqual-width row with other small items
StatGroupstatFull width
AreaChart, LineChart, BarChart, ...chartTwo charts: 2:1 split. Three: equal thirds. Single: full width
DataTabletableFull width
DashboardHeaderheaderFull width
MetricGrid.SectionfullFull width (labeled divider)
Unknown / customunknownFull 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 chart

Props

PropTypeDescription
children*
React.ReactNode

MetricUI components. Layout is auto-detected from component types.

columns
number

Max small items (KPIs, Gauges) per row.

gap
number

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

PropTypeDefaultDescription
titlestring(required)Section label.
subtitlestringSecondary label below the title.
descriptionstring | ReactNodeContent for the info popover.
actionReactNodeRight-aligned action slot.
badgeReactNodeInline badge after the title.
borderbooleanfalseShow a border line above the section.
classNamestringAdditional CSS classes.

MetricGrid.Item Props

PropTypeDefaultDescription
span"sm" | "md" | "lg" | "full" | numberOverride the auto-detected column width.
childrenReactNode(required)The component to render.
classNamestringAdditional 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.