Meter

A reading inside a known range: storage used, a plan's quota, a battery. It shares Progress's bar, and adds role="meter", locale-aware formatting and thresholds that recolour the fill.

Storage

Installation#

# One-time setup (tokens + lib helpers)npx koalaui-cli@latest init# Add this component (its dependencies come along)npx koalaui-cli@latest add meter

Usage#

Pass value, and min and max when the range is not 0 to 100. A bare <Meter /> renders just the bar; give it an aria-label.

usage.tsxTSX
import {  Meter,  MeterLabel,  MeterValue,  MeterTrack,  MeterIndicator,} from "@/components/ui/meter"export function Example() {  return (    <Meter value={64}>      <MeterLabel>Storage</MeterLabel>      <MeterValue />      <MeterTrack>        <MeterIndicator />      </MeterTrack>    </Meter>  )}

Anatomy#

import {  Meter,  MeterLabel,  MeterValue,  MeterTrack,  MeterIndicator,} from "@/components/ui/meter"<Meter>  <MeterLabel />  <MeterValue />  <MeterTrack>    <MeterIndicator />  </MeterTrack></Meter>

Meter vs Progress#

Progress reports how far a task has got: an upload, an import. It only moves forward and it ends. A meter reports how much of something there is: disk used, seats taken, charge left. It can go down as well as up, and nothing is ever finished. Screen readers hear the difference (role="progressbar" against role="meter"), so pick by meaning, not by look. The two share one bar, so they always sit together cleanly.

Plan usage#

Quotas in a card. Each meter turns warning past 75% and destructive past 90%, and MeterValue phrases the limit next to the reading.

Pro plan
Resets on November 1
API requests
Seats
Storage

Thresholds#

low, high and optimum work as on the HTML <meter>. They split the range into an optimal, a suboptimal and a critical region, and the fill takes success, warning and destructive. Put optimum at 0 when lower is better (a disk), at the top when higher is better (a battery). The root carries the region as data-level.

Disk
Disk
Disk
Battery
Battery
Battery

Formatted values#

format takes Intl.NumberFormat options and drives both the readout and aria-valuetext. Without it, the reading is a whole percentage of the range; a percent style reads the share of the range too. The visitor’s locale applies after hydration, so the server render never disagrees with the browser. Pass locale to fix one.

Default
Percent, one decimal
Currency
Unit

Live readings#

The fill glides between readings on the motion tokens, and the readout uses tabular figures so it never jitters as the number changes.

Memory

Sizes#

The Progress height scale: xs (4px), sm (the default), md and lg.

xs
sm
md
lg

Tones#

For a reading with no good or bad side, pin the colour with tone. It wins over the thresholds.

Brand
Info
Success
Foreground

Accessibility#

The root is role="meter" with aria-valuenow, aria-valuemin, aria-valuemax and an aria-valuetext built from format. A composed MeterLabel names it; otherwise pass aria-label. MeterValue is hidden from assistive tech so the reading is not announced twice. Colour is never the only signal: keep the value visible when a threshold matters.

API reference#

Meter

The root. Renders a <div role="meter"> laid out as a two column grid: label left, value right, track across both. With no children it renders a bare track. Forwards all native <div> props.

PropTypeDefaultDescription
value*number-The reading. Clamped to min and max for display and for aria-valuenow.
minnumber0Lower bound of the range.
maxnumber100Upper bound of the range.
lownumberminUpper bound of the low region.
highnumbermaxLower bound of the high region.
optimumnumbermidpointThe ideal reading. Decides which region is optimal, as on the HTML <meter>.
formatIntl.NumberFormatOptions-Formats the readout and aria-valuetext. Without it, a whole percentage of the range. A percent style also reads the share of the range.
localeIntl.LocalesArgument-Locale for the readout. Defaults to the visitor's, applied after hydration (en-US on the server).
getAriaValueText(formattedValue: string, value: number) => string-Phrase the screen reader text yourself. An explicit aria-valuetext still wins.
size"xs" | "sm" | "md" | "lg""sm"Bar height: 4, 6, 8 or 12px. The Progress scale.
tone"brand" | "foreground" | "success" | "warning" | "destructive" | "info"-Pins the indicator colour. Without it the thresholds pick one, or brand when there are none.
Data attributeDescription
data-level"optimal", "suboptimal" or "critical". Only set when low, high or optimum is passed.

MeterLabel

The visible name. When composed in, it also becomes the meter's accessible name through aria-labelledby. Forwards all native <span> props.

MeterValue

The readout, in tabular figures and aria-hidden (the root already carries it as aria-valuetext). Forwards all native <span> props.

PropTypeDefaultDescription
children(formattedValue: string, value: number) => ReactNode-Phrase the readout yourself: "45.2 GB of 100 GB". Defaults to the formatted value.

MeterTrack

The groove, Progress's track slot. Spans both grid columns. Forwards all native <div> props.

MeterIndicator

The fill, Progress's indicator slot. Its width is the reading's share of the range and it glides on change. Forwards all native <div> props.

Data attributeDescription
data-levelMirrors the root's level, when thresholds are set.

FAQ#

Progress for a task moving toward done, Meter for a measurement within a range. If the value can go down, or the bar never finishes, it is a Meter.