Skip to content

Meter

A gauge for a scalar value within a known range — utilization, quota, capacity. The web-platform sibling of ProgressBar: <meter> is "how full", <progress> is "how far along" (ARIA roles meter vs progressbar). Use ProgressBar for task progress; use Meter for level gauges.

The filled segment is painted as a background block (not fill characters) so a short semantic label — "13h 20m" until reset, "78%", "1.2 GB" — can sit ON the bar. The label is fitted whole into the wider segment; candidates are semantic alternatives (richest-to-smallest), never character slices, so the label is complete or absent, never clipped.

Import

tsx
import { Meter } from "silvery"

Props

PropTypeDefaultDescription
valuenumber--Fill fraction 0-1, clamped
widthnumberautoWidth in columns (uses available width via useBoxSize)
fillColorstring"$bg-accent"Filled-segment paint (background)
emptyColorstring"$fg-muted"Empty-track ink: emptyChar foreground + backdrop behind an empty-segment label
emptyCharstring"░"Empty-track glyph (1 column)
emptyBackgroundColorstring--Solid paint behind the empty track; use with emptyChar=" " for a block track
overlayMeterOverlay | null--Label fitted into the larger viable filled/empty segment

MeterOverlay

PropTypeDefaultDescription
candidatesreadonly string[]--Richest-to-smallest semantic labels; never character-clipped
colorstringsegment-aware¹Ink for primary label chars (digits, spaces, punctuation)
secondaryColorstring"$fg-muted"Ink for secondary chars, e.g. unit letters
isSecondaryChar(char: string) => booleannoneClassifier for secondary chars
filled / emptyMeterLabelColors--Per-segment ink overrides when one pair can't serve both paints

¹ "$fg-on-accent" on the filled segment (pairs with the default fill), "$fg" on the empty segment.

Usage

tsx
// Basic utilization gauge
<Meter value={0.7} width={10} />

// Threshold-colored quota bar with a time-until-reset label
<Meter
  value={used / total}
  width={12}
  fillColor="$bg-warning"
  overlay={{
    candidates: ["13h 20m", "13h"],
    secondaryColor: "$fg-muted",
    isSecondaryChar: (c) => c >= "a" && c <= "z",
  }}
/>

// Solid block track (CLI table look)
<Meter value={0.4} width={10} emptyChar=" " emptyBackgroundColor="$bg-muted" />

Helpers

The fit machinery is exported for headless/CLI reuse:

  • fitSegmentLabel({ candidates, filledCells, emptyCells }) — selects one whole label for a two-segment meter: larger segment wins, ties keep the filled placement, filled labels left-align, empty labels right-align, no fit → null (never clips).
  • leadingUnitLabelCandidates(["3d", "20h", "10m"])["3d 20h", "3d"] — richest-to-leading-unit candidates, capped at two units.
  • meterFilledCells(value, width) — the shared value→cells rounding used by both Meter and ProgressBar.

Headless / CLI

Meter renders through renderString for one-shot stdout output (styled output is SGR-only — no cursor or mode sequences):

tsx
const bar = await renderString(<Meter value={0.18} width={10} overlay={…} />, {
  width: 10,
  height: 1,
  trimTrailingWhitespace: false,
})
process.stdout.write(bar)

See Also

  • ProgressBar -- task progress (determinate/indeterminate)
  • Spinner -- animated loading indicator