Meter
A measurement shown against a range — a reading, not a task.
Installation
npx shadcn@latest add https://qure-ui.qure.ai/r/meter.jsonUsage
import { Meter, MeterLabel, MeterTrack, MeterValue } from '@/components/ui/meter'<Meter value={68}>
<MeterLabel>PACS node storage</MeterLabel>
<MeterValue />
<MeterTrack />
</Meter>value is required. The range is 0–100 unless you give it min and max.
Meter is not Progress
They look almost identical and mean opposite things, so this is the section worth reading.
| Meter | Progress | |
|---|---|---|
| The number is | a measurement taken now | how much of a job is done |
| It moves because | the thing being measured changed | work happened |
| Reaching the end is | often bad — a full disk, a dose at the limit | the goal |
| ARIA role | meter | progressbar |
| A screen reader says | "68 percent" | "68 percent, busy" |
Storage used, beds occupied, dose against a notification level, an AI confidence score, agreement between two readers — all meters. None of them are heading anywhere, and dressing them as progress tells the reader to wait for something that is never going to happen.
The reverse mistake is quieter but worse: a genuine long-running job shown as a meter loses the
busy state, and assistive technology stops telling the user that anything is in flight.
If the answer to "what happens when it reaches 100%?" is "nothing, it is just full", it is a meter.
Composition
<Meter> {/* owns value, min, max and the aria plumbing */}
<MeterLabel> {/* the name — linked to the root by the primitive */}
<MeterValue> {/* the figure, formatted */}
<MeterTrack> {/* the bar; renders its own indicator */}
</Meter>The parts are laid out on a two-column grid: label left, value right, track spanning both. Drop
MeterLabel or MeterValue and the grid closes up, so a bare bar in a table row needs no extra
wrapper — give the root an aria-label instead.
Tone
tone is yours to choose, not the component's. A meter has no idea whether 82% is good news, and
one that guessed would be wrong the first time somebody measured a thing where low is bad. Here
the CTDIvol readings are coloured against the 20 mGy notification level for an adult head CT.
Colour is never the only signal — the figure is always spelled out beside the bar.
A range that is not a percentage
qXR confidence runs 0–1, so max={1} and format turns 0.84 into 84% for display without the
component pretending the underlying number was ever a percentage. getAriaValueText supplies the
sentence a screen reader reads, which should name the finding — "84% confidence, consolidation"
rather than a bare number arriving out of context.
A block of readings
Capacity is the classic case: several readings taken at the same moment, none of them going anywhere, all of them worth knowing before you accept another study. Keep the row gap generous — meters stacked tightly read as one segmented bar.
In a table
| Accession | Finding | Confidence |
|---|---|---|
| ACC-4471902 | Consolidation | |
| ACC-4471887 | Nodule | |
| ACC-4471863 | Pneumothorax |
size="sm" halves the track so a row keeps its height. There is no label because the column
heading is the label, but the root still needs an aria-label: a screen reader reading across
the row gets no help from a heading three rows up.
API Reference
Everything Base UI's Meter accepts, plus two of ours on the root.
Prop
Type
MeterValue takes a function as its children — (formatted, value) => ReactNode — for when the
figure needs a unit or a denominator the formatter cannot supply.