UsageCard
A single Neon consumption metric on the MetricCard shell, deriving label, format, unit, total, sparkline, and delta from raw per-project samples.
UsageCard is the single-metric building block UsagePanel composes from. Hand it the raw per-project consumption samples in their native units — seconds for compute, bytes for storage — and the metric kind; it knows the rest. Compute and writes sum across the window, storage reads the latest level, seconds render as hours, bytes format themselves, and a previousTotal turns into a signed delta. It is presentational: the samples come from a server component or the Data API, never a key in the browser.
Metrics
Each metric carries its own label, format, unit, and aggregation, so the same card reads compute, storage, or bytes written without per-call bookkeeping.
Install
npx shadcn@latest add https://ui.neon.com/r/usage-card.json
Usage
import { UsageCard } from "@/components/neon-ui/usage-card";
<UsageCard
metric="compute"
windowLabel="14d"
data={[
{ label: "Jul 3", value: 11_160 },
{ label: "Jul 4", value: 9_360 },
// ...native seconds per day
]}
previousTotal={129_600}
comparisonLabel="vs previous 14 days"
/>;
Wiring to Neon
A server component pulls two windows of daily consumption, keeps the current one as samples and sums the prior one for the delta:
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();
Read compute_time_seconds (or synthetic_storage_size_bytes, written_data_bytes, active_time_seconds) off each timeframe into UsagePoints and pass them straight through.
Props
UsageCard forwards every prop the MetricCard shell accepts — isLoading, error, className, and the rest — while owning the metric semantics below.
metric"compute" | "active-time" | "storage" | "written-data"
Which consumption metric this card reads.
"compute" | "active-time" | "storage" | "written-data"dataUsagePoint[]
The window's samples, newest last, in native units (seconds for time metrics, bytes for data metrics).
UsagePoint[]previousTotal?number
Previous-window total in native units. When set, drives the signed delta.
numberlabel?string
Overrides the metric's default label.
stringwindowLabel?string
Appended to the label as quiet context, e.g. "14d".
stringcomparisonLabel?string
Context shown with the delta, such as "vs previous 14 days".
stringisLoading?boolean
Render the MetricCard skeleton.
booleanfalseerror?Error | string | null
Render the MetricCard error state with the message.
Error | string | nullnullHow values are derived
- compute, active-time — native seconds summed across the window, shown in hours (
hrs). - written-data — native bytes summed across the window, formatted as a size.
- storage — a level, not a total: the card reads the latest sample and formats it as a size.
- delta — only when
previousTotalis set: the signed percentage change of the current window against it. No comparison base, no delta — the card never invents one. - sparkline — every sample maps to a trend point in the displayed unit; an empty
dataarray drops the chart rather than faking one.
Accessibility
UsageCard inherits the MetricCard shell: the sparkline is keyboard accessible (focus it, then Left/Right, Home, End to inspect points), values are announced through a polite live region, and the signed delta pairs an icon with text so meaning never rests on color alone.