Skip to content
Neon UI
Esc
navigateopen⌘Jpreview
On this page

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.

Compute · 14d
+13%vs previous 14 days
40.8hrs

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.

Compute · 14d
+13%vs previous 14 days
40.8hrs
Storage · 14d
+19%vs 14 days ago
3.4 GB
Data written · 14d
+17%vs previous 14 days
13.5 GB

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.

PropType
metric"compute" | "active-time" | "storage" | "written-data"

Which consumption metric this card reads.

Type"compute" | "active-time" | "storage" | "written-data"
dataUsagePoint[]

The window's samples, newest last, in native units (seconds for time metrics, bytes for data metrics).

TypeUsagePoint[]
previousTotal?number

Previous-window total in native units. When set, drives the signed delta.

Typenumber
label?string

Overrides the metric's default label.

Typestring
windowLabel?string

Appended to the label as quiet context, e.g. "14d".

Typestring
comparisonLabel?string

Context shown with the delta, such as "vs previous 14 days".

Typestring
isLoading?boolean

Render the MetricCard skeleton.

Typeboolean
Defaultfalse
error?Error | string | null

Render the MetricCard error state with the message.

TypeError | string | null
Defaultnull

How 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 previousTotal is 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 data array 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.