Usage meter

Show what fills an allowance and how close it is to the limit.

meterusagestorage
Preview
Usage meter preview
Workspace storage36.0 GB free

64.0 GB of 100 GB used

When to use

  • Quota against a fixed allowance, such as storage, seats, or API calls.
  • Billing pages that should show what takes the space and how close the plan is to full.
  • Plans that can go over the limit, where the overage should be clear without relying on color.

When not to use

  • Use progress for task completion.
  • Use bar-chart to compare categories without a limit.
  • Use gauge or stat-card for a single headline metric.

shadcn CLI

Also installs (1)

  • manicat-foundation
Manual install(+)
registry.jsonjson
{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "usage-meter",
  "type": "registry:ui",
  "title": "Usage meter",
  "description": "Show what fills an allowance and how close it is to the limit.",
  "categories": [
    "feedback"
  ],
  "dependencies": [
    "lucide-react",
    "motion"
  ],
  "registryDependencies": [
    "https://manicat.viraza.net/r/manicat-foundation.json"
  ],
  "files": [
    {
      "path": "registry/components/usage-meter/usage-meter.tsx",
      "type": "registry:component",
      "target": "@components/manicat/usage-meter/usage-meter.tsx"
    },
    {
      "path": "registry/components/usage-meter/usage-meter.module.css",
      "type": "registry:component",
      "target": "@components/manicat/usage-meter/usage-meter.module.css"
    }
  ],
  "docs": "Docs and live preview: https://uiarc.dev/components/usage-meter",
  "meta": {
    "tier": "free",
    "kind": "component",
    "docs": "https://manicat.viraza.net/components/usage-meter",
    "markdown": "https://uiarc.dev/components/usage-meter/markdown",
    "tags": [
      "meter",
      "usage",
      "storage"
    ]
  }
}

Usage

Install the component, then copy this into your app. Change the content and the props to fit your screen.

example.tsxtsx
"use client";

import { useState } from "react";
import { UsageMeter } from "@/components/manicat/usage-meter/usage-meter";
import { Button } from "@/components/manicat/button/button";

export function UsageMeterExample() {
  const [used, setUsed] = useState(64);

  return (
    <div className="grid w-full max-w-sm gap-3">
      <UsageMeter
        label="Workspace storage"
        limit={100}
        unit="GB"
        segments={[
          { id: "db", label: "Database", value: used * 0.5 },
          { id: "media", label: "Media", value: used * 0.4 },
          { id: "logs", label: "Logs", value: used * 0.1 },
        ]}
      />
      <Button size="sm" variant="secondary" onClick={() => setUsed((value) => (value > 90 ? 20 : value + 20))}>
        Add 20 GB
      </Button>
    </div>
  );
}

Examples

Real screens rather than isolated props. Switch to Code to copy a whole example into your project.

Storage quota A segmented meter that shows what fills the quota, with a button to simulate growth.

Storage quota A segmented meter that shows what fills the quota, with a button to simulate growth. preview
Workspace storage36.0 GB free

64.0 GB of 100 GB used

Keyboard interactions

KeysAction
ArrowLeft / ArrowRight / ArrowUp / ArrowDownMoves between legend items (roving tab stop).
Home / EndJumps to the first or last legend item.
Enter / SpacePins or unpins the focused category.
EscapeClears the pinned category.

Accessibility

  • The meter is a role="group" labelled by its title; the bar is role="img" with a full text summary of every segment and the status.
  • Rolling numbers are aria-hidden with screen-reader-only text alongside.
  • Status changes (near limit, over limit, growing overage) are announced in a polite live region.
  • Legend items are buttons with aria-pressed and labels like "Media, 14.2 GB".

Motion

  • Segments grow in left to right once scrolled into view, then re-flow on one spring each when values change; crossing the limit fades in a hatched overage and limit marker.
  • Digits roll like an odometer in the direction the number moved; the status badge springs to its new width.
  • Reduced motion jumps values and swaps text with short fades.

Responsive behavior

  • The legend is an auto-fit grid of 108px minimum columns, so it wraps to fewer columns on narrow cards.
  • Hovering the bar highlights a category on mouse; on touch a tap pins it instead.
  • The caption ellipsizes on one line, so long labels do not push the layout.

Performance

  • Segments animate in once via useInView at 40% visibility, then re-flow on springs when values change.
  • A ResizeObserver tracks the bar width; up to four segments read clearly.

Notes for AI

  • Use for quota against a fixed allowance: storage, seats, API calls. Use progress for task completion and bar-chart for comparing categories without a limit.
  • Keep segment ids stable across renders so updates animate instead of remounting.