Skip to content

Meter

hc-meter is applied to a standard <meter> element — the scalar measurement within a known range (disk quota, score, capacity), completing the pair with hc-progress (task progress). The native element retains its role="meter" semantics and the value / min / max / low / high / optimum attributes; only the visual chrome is replaced via appearance: none and per-vendor pseudo-elements.

7 of 10

The text child (7 of 10) is the fallback for user agents that don’t render <meter> — keep it meaningful.

low / high / optimum tell the browser how to classify the current value; the component maps the three regions onto the status tokens — no data-variant needed, the color is derived from the data:

RegionWhenColor token
optimumvalue in the best bandmeter.optimum-fill (success)
suboptimumvalue one band awaymeter.suboptimum-fill (warning)
criticalvalue two bands awaymeter.critical-fill (error)
42%82%97%

Flip optimum toward max for “high is good” scales (battery, score) — the same bands then colour in the opposite direction.

data-size accepts sm, md (default), and lg.

40%40%40%
UseElement
Task completion moving toward done<progress class="hc-progress">
A measurement within a known range (quota, score, load)<meter class="hc-meter">

A <meter> never has an indeterminate state, and a <progress> has no good/bad regions — the elements encode the distinction for assistive tech, so pick by meaning, not by look.

A <meter> is a normal DOM node — swap it like any other element, e.g. a quota cell that re-renders after an upload:

<meter class="hc-meter" id="quota" min="0" max="100"
low="70" high="90" optimum="10" value="82"
data-hx-get="/account/quota" data-hx-trigger="hc:uploaded from:body"
data-hx-swap="outerHTML">82%</meter>

hc:uploaded here is your application’s event (fired by whatever completes the upload), not a kit event — any htmx trigger works, e.g. every 30s for a polling quota. The region color updates itself on swap — it is derived from the new value by the browser, not by a script.

  • Always give the element an accessible name — a wrapping <label for> or an aria-label. The element itself is exposed as a meter with its value; no aria-valuenow mirroring is needed.
  • Keep the fallback text child in sync with value server-side — it is also what copy-paste and reader modes see.
  • Color is not the only signal: the value/max pair is in the accessibility tree, and the visible label should carry the number for sighted users too (as in the demos above).

Component tokens (in component.tokens.json):

Token pathPurpose
meter.heightTrack height.
meter.radiusTrack corner radius.
meter.bgTrack background.
meter.optimum-fillFill in the best region (success).
meter.suboptimum-fillFill one band away (warning).
meter.critical-fillFill two bands away (error).
meter.sm.height / lg.heightSize variants.
Show the generated CSS variables
--hc-meter-height | -radius | -bg
--hc-meter-optimum-fill | -suboptimum-fill | -critical-fill
--hc-meter-sm-height | -lg-height
  • Progress — task completion; the <progress> half of the pair.
  • Sparkline — the trend next to the current measurement.
  • Status colors — the shared success / warning / error tokens the regions map onto.