MetricCard
Analytics card with a formatted value, signed delta, and interactive Visx sparkline.
MetricCard is the reusable analytics card the rest of the registry builds on: UsageCard, CostMeter, and HealthCard all compose from it. It takes a value, an optional signed delta, and an optional labeled trend series that renders as an interactive sparkline. Loading and error states are props, so it drops into any data layer.
Variants
Data formats
Number, byte, percentage, duration, and currency formatting use the same card anatomy.
Delta states
Comparison context makes positive, negative, and unchanged deltas meaningful.
System states
Loading, error, and no-trend states preserve the card’s layout without inventing chart data.
Install
npx shadcn@latest add https://ui.neon.com/r/metric-card.json
Usage
import { MetricCard } from "@/components/neon-ui/metric-card";
<MetricCard
format="number"
label="Active connections"
value={42}
delta={12}
trend={[18, 22, 27, 31, 34, 38, 42]}
/>;
Wiring to Neon
The presentational component takes data as props. A server component fetches real consumption from the Neon API and passes it down:
import { createNeonClient } from "@/lib/neon-client";
const neon = createNeonClient(process.env.NEON_API_KEY);
const { data } = await neon.consumption
.perProject({
from: from.toISOString(),
to: now.toISOString(),
granularity: "daily",
project_ids: [projectId],
})
.all();
Props
labelstring
Metric name shown above the value.
stringvaluenumber | string
The metric value. Strings render verbatim; numbers are formatted.
number | stringdelta?number
Signed change vs the previous period. Positive is green, negative is red.
numbercomparisonLabel?string
Context shown with the delta, such as "vs yesterday".
stringtrend?(number | MetricTrendPoint)[]
Series driving the sparkline. Labeled points produce useful tooltips; an empty array renders the no-trend state.
(number | MetricTrendPoint)[]format?"number" | "bytes" | "percent" | "currency" | "duration"
How a numeric value is formatted.
"number" | "bytes" | "percent" | "currency" | "duration""number"unit?ReactNode
Suffix rendered after the value, e.g. "hrs".
ReactNodeisLoading?boolean
Render a skeleton placeholder.
booleanfalseerror?Error | string | null
Render an error state with the message.
Error | string | nullnullFormatting
format controls how a numeric value is displayed:
number— grouped integer (1,204)bytes— human-readable size (3.6 GB)percent— value with a%suffix (99.2%)currency— USD ($284.50)duration— value in seconds ash/m/s(2h 8m)
Accessibility
The sparkline is keyboard accessible. Focus it and use Left/Right, Home, or End to inspect points. The active label and formatted value are announced through a polite live region, and the signed delta uses both an icon and text so meaning never relies on color alone.