Usage meters
ProWhat's used against each limit: seats, an environment's daily API allowance, agent work. The bar's fill carries severity (accent → warning → danger past 75% and 90%); its track is a lighter step of the same hue. Where the plan sets no limit the meter says so and shows the count alone — it never draws a bar against a made-up cap. A usage's estimate (your own figure, such as a quote) is a tick on the bar with its label, never a projection the meter makes up. When your server formats the figures ("about $4"), usedText, limitText and estimateText are shown as written; the numbers only place the bar.
Usage that's done but not metered yet (pending) is a striped part of the bar after what's used, said in words, and how far a run may still go past the limit (mayExceedBy) is said under the meter: both are your figures, never the meter's projection.
Preview
Install
First time? Get started sets up the registry and theme. Or with shadcn directly: npx shadcn@latest add @candor/usage-meters
Brings in: locale, ops, relative-time, utils
Usage
"use client"
import { UsageMeters } from "@/components/usage-meters"
import type { Usage } from "@/lib/ops"
const usages: Usage[] = [
{ label: "Seats", used: 6, limit: 8, unit: "seats", note: "2 pending invites would use both." },
{ label: "CI minutes today · Production", used: 864, limit: 1_000, unit: "minutes", resetsAt: new Date(Date.now() + 9 * 3_600_000).toISOString() },
{ label: "Agent runs this month", used: 412, limit: null, unit: "runs" },
// estimate: your own figure (a quote, a forecast), marked on the bar and labelled; the meter never projects one.
{ label: "Spend on this job", used: 1.2, limit: 4, unit: "USD", estimate: 2.6, estimateLabel: "Quoted" },
// pending: done but not metered yet; mayExceedBy: your provider's own figure for how far a run may go past the limit.
{ label: "Agent spend today", used: 7.4, limit: 10, unit: "USD", usedText: "$7.40", limitText: "$10", pending: 1.1, pendingText: "about $1.10", mayExceedBy: 2, mayExceedByText: "$2" },
]
export default function Example() {
return <UsageMeters className="max-w-xl" usages={usages} />
}<UsageMeters>
| Prop | Type | Default | Description |
|---|---|---|---|
| usagesrequired | Usage[] | — | One meter per limit: what's used, the limit (null when there is none), the unit and when it resets. |
| className | string | undefined | — | Extra classes for the outer element. |
Strings
The fixed words, in English by default. Change any of them under usageMeters in <LocaleProvider strings={{ … }}>; the table is exported as usageMetersStrings.
| Key | English |
|---|---|
| usage | Usage |
| noCap | No cap on your plan. |
| resets | Resets {time}. |
| estimate | Estimate |
| estimateValue | {label}: {value} |
| pending | {value} not yet metered |
| mayExceed | May go over the limit by up to {value}. |