Usage meter
FreeA segmented bar showing how an allowance is used, with a warning near the limit.
pnpm dlx shadcn@latest add https://caliperui.site/r/usage-meter.jsonAPI requests · day 9 of 31
742 / 1,000 k
At this pace you reach about 2.56M by 31 Oct: roughly $78 extra.
Within limit
When to use #
Use it for
- Storage, seats and quota shown as parts of a whole.
- You want a visible warning as the limit nears.
Skip it when
- There is no limit; use a metric.
- Only one value matters; use a progress bar.
Installation #
pnpm dlx shadcn@latest add https://caliperui.site/r/usage-meter.json
Adds its 2 files to components/ui/, each with its own stylesheet, and installs their packages. No account needed. The first part also adds Caliper UI’s tokens; import them once as in Installation.
Usage #
This is the code behind the preview above.
import { useState } from "react" import { Button } from "@/components/ui/button" import { UsageMeter } from "@/components/ui/usage-meter" export function StorageMeter() { const [used, setUsed] = useState(742); const [day, setDay] = useState(9); const projected = Math.round((used / day) * 31); const over = projected - 1000; const consequence = used > 1000 ? `Over the limit by ${used - 1000}k. Extra requests are $0.05 per 1k: $${((used - 1000) * 0.05).toFixed(2)} so far.` : over > 0 ? `At this pace you reach about ${(projected / 1000).toFixed(2)}M by 31 Oct: roughly $${Math.round(over * 0.05)} extra.` : `Projected ${projected}k by 31 Oct. Comfortably inside the limit.`; return ( <div className="grid w-full max-w-md gap-3"> <UsageMeter label={`API requests · day ${day} of 31`} unit="k" limit={1000} projected={projected} consequence={consequence} segments={[ { id: "api", label: "REST", value: Math.round(used * 0.7) }, { id: "webhooks", label: "Webhooks", value: used - Math.round(used * 0.7) }, ]} /> <div className="flex flex-wrap gap-2"> <Button size="sm" variant="secondary" onClick={() => setUsed((value) => value + 120)}>+120k requests</Button> <Button size="sm" variant="secondary" onClick={() => setDay((value) => Math.min(31, value + 1))}>Advance a day</Button> <Button size="sm" variant="ghost" onClick={() => { setUsed(742); setDay(9); }}>Reset</Button> </div> </div> ); }
API reference #
UsageMeter
component
Accessibility #
It exposes group and img semantics, with aria-label, aria-pressed and aria-live kept in step with state. Changes that matter are announced through a live region.
Motion #
It declares no animation in its component source. Any transition comes from its stylesheet, which uses the duration tokens that collapse to instant under prefers-reduced-motion.