A bar that shows where one measured value sits within a known range, with the words that name it and the figure it reaches, such as "Reporting live" at "82%", for the share of a network's vehicles that report their position.
When to use
Use Meter for a measured value within a known range that changes on its own, such as the share of a network's vehicles reporting live.
Kongens Nytorv
Metro M1, M2 and M3.
Variants and states
| Rest | |
|---|---|
| Neutral | Reporting live |
| Success | Reporting live |
| Warning | Reporting live |
| Danger | Reporting live |
| Info | Reporting live |
- RestReporting live
- RestReporting live
- RestReporting live
- RestReporting live
- RestReporting live
Props
| Name | Type | Default | Description |
|---|---|---|---|
label* | ReactNode | — | What the meter measures, in a few words, such as "Reporting live": shown above the track, and the meter's accessible name. Required |
value* | number | null | — | Required. The measured value, between min and max; one outside them is shown at the nearest end. null, or a number that is not finite, when no data gives it: Meter then shows "—" over an empty track and says "Unknown" (CR-5) |
color | 'neutral' | 'success' | 'warning' | 'danger' | 'info' | 'neutral' | The intent: what the fill means. neutral is a plain measure in ink; the status intents tint the fill for a value that is good or bad news, such as the live share's. Always beside words that say what the value means: colour is never the only sign |
locale | LocalesArgument | The PerronProvider's locale | The locale Intl.NumberFormat formats the figure in: "82%" in English, "82 %" in Danish, Swedish and Norwegian. Left out, the nearest PerronProvider's |
unknownLabel | string | The locale's | Overrides "Unknown", heard in place of the figure when the value is unknown |
className | string | — | Joined after pn-Meter on the root |
style | CSSProperties | — | Reaches the root |
ref | Ref<HTMLDivElement> | — | Reaches the root element |
slotProps | { label?: MeterLabelProps | undefined; value?: MeterValueProps | undefined; track?: MeterTrackProps | undefined; indicator?: MeterIndicatorProps | undefined; } | — | Props for each part: label, value, track, indicator. |
label (required)ReactNode, default —- What the meter measures, in a few words, such as "Reporting live": shown above the track, and the meter's accessible name. Required
value (required)number | null, default —- Required. The measured value, between
minandmax; one outside them is shown at the nearest end.null, or a number that is not finite, when no data gives it: Meter then shows "—" over an empty track and says "Unknown" (CR-5) color'neutral' | 'success' | 'warning' | 'danger' | 'info', default'neutral'- The intent: what the fill means.
neutralis a plain measure in ink; the status intents tint the fill for a value that is good or bad news, such as the live share's. Always beside words that say what the value means: colour is never the only sign localeLocalesArgument, default The PerronProvider's locale- The locale
Intl.NumberFormatformats the figure in: "82%" in English, "82 %" in Danish, Swedish and Norwegian. Left out, the nearest PerronProvider's unknownLabelstring, default The locale's- Overrides "Unknown", heard in place of the figure when the value is unknown
classNamestring, default —- Joined after
pn-Meteron the root styleCSSProperties, default —- Reaches the root
refRef<HTMLDivElement>, default —- Reaches the root element
slotProps{ label?: MeterLabelProps | undefined; value?: MeterValueProps | undefined; track?: MeterTrackProps | undefined; indicator?: MeterIndicatorProps | undefined; }, default —- Props for each part:
label,value,track,indicator.
Use it
import { Meter } from '@mylder/perron'Ask your agent
get_reference({ library: "base-ui", component: "Meter" })Keyboard and ARIA
Meter has no keys of its own and is never focusable: a meter is not a control. A caller who makes it a link through render brings that element's own keys.
| Key | Does | From |
|---|---|---|
| None | Meter is not focusable or operable | Perron |
| Element | Role | Accessible name from | States announced |
|---|---|---|---|
root | meter, from Base UI | aria-labelledby, the label part's id, so the caller's label. Base UI's Meter.Label registers its id on the client only, so server-rendered markup has no aria-labelledby until hydration | aria-valuenow, aria-valuemin, aria-valuemax, and aria-valuetext: the figure, "82%", or "Unknown" when unknown (CR-5) |
label | presentation, from Base UI | Not named; its text is the root's name | None |
value | Hidden: aria-hidden="true", from Base UI | Not read; aria-valuetext says it | None |
track, indicator | None (generic div) | Not named; they hold no text | None |
Base UI's "x" span | presentation, visually hidden | Chromium exposes it as the text "x" inside the meter; Meter keeps Base UI's root (CR-1) until the maintainer decides, and no screen reader has confirmed whether it is heard | None |
What axe won't catch, from the contract, each with how this component meets it:
- Everything the eye is told, the ear is told, for every shape each prop accepts: the eye gets the label, the figure and the fill's length; the ear the label as the name and the figure as
aria-valuetext, which Base UI keeps the same text as the shown figure, or a fuller one fromgetAriaValueText. An unknown value is "—" and an empty track for the eye, "Unknown" for the ear (CR-5). A statuscolorsays good or bad by colour alone, so the caller says it in words too, in the label or beside the meter (Do and don't); in forced colours the tint goes and the figure and the words still carry it. - Every landmark and named region has an accessible name: none here; the root is a
meter, named by its label, not a landmark or region. - Every default label can be overridden:
unknownLabel. - Every shape the type accepts renders, in every variant:
labelis aReactNode, and a string, a number, an element and a list each render in everycolor;valuerenders0,min,max, a value outside the range (clamped), a fraction,null,NaNandInfinity(the last three unknown), whichMeter.test.tsxrenders each of. TheDefaultstory gives a string label and a number. - A hidden copy kept for animation is
aria-hidden, and a collapsed region isinert: none here; the fill's transition moves one element, and nothing collapses. The figure isaria-hiddenbecausearia-valuetextsays it, not for animation. - Native semantics first: no native element says "a value in a range" with Perron's look and Base UI's API (
<meter>draws its own bar), so Base UI'srole="meter"with itsaria-value*attributes, and no ARIA of Perron's beyond thearia-valuetextof an unknown value. - Focus moves in reading order and returns on close: Meter takes no focus and opens nothing.
- Every target is at least
size.target-minsquare: no target; Meter is not pressed. - Loops stop when the system asks for less motion: no loop; the fill's change is a transition over
duration.meter, which the tokens shorten to 0.01 ms under reduced motion (CR-6).
Owned strings
Every word Meter shows comes from the caller, through label, or from Base UI's formatting of the number, but for the one it announces when the value is unknown.
| Key | English | Override | Seen or heard where |
|---|---|---|---|
unknown | "Unknown" | unknownLabel | The root's aria-valuetext when the value is unknown, heard after the label (CR-5) |
unknown is the key packages/perron/src/locale/en.ts already has for Stat, FactList and Count, so its Danish, Swedish and Norwegian are there; its JSDoc line adds Meter to the components it names. After the label it reads "Reporting live, Unknown", as Stat's does. The figure's digits and percent sign carry no letter, so expectOwnedStrings passes them in every locale; Base UI's "x" is the one letter it would flag (CR-9).
Do and don't
For a caller using the component, with the reason. Each row is a rule: a must row's Don't is never right, a should row's needs a reason, and Checked by says what catches the Don't in a caller's code.
| Rule | Level | Do | Don't | Checked by |
|---|---|---|---|---|
| DD-1 | must | Use Meter for a measure within a known range that changes on its own, such as the share of vehicles reporting live | Use it for the progress of a task, such as a load: a meter is a measurement, and a task's progress is a progressbar, which Progress draws | review |
| DD-2 | must | Pick color from the value on the screen that knows what good is, such as the live share's 70% and 40%, and say it in words beside it | Let the tint alone say good or bad: colour tells no screen reader and no colour-blind person, and forced colours drop it | review |
| DD-3 | must | Pass null when no data gives the value, so Meter shows "—" and says "Unknown" | Pass 0 or a guess when the value is unknown: an empty fill at "0%" claims a figure the data never gave | review |
| DD-4 | must | Name the meter in a few words in label: "Reporting live", "Trips run today" | Leave the name to the layout: a meter with no name tells the ear a number and nothing about it | review |
| DD-5 | must | Give getAriaValueText the fuller words when the figure shows them, such as "1 046 of 1 204" through slotProps.value.children | Change the shown figure and leave the ear on the percentage: the eye and the ear then hear different numbers | review |
| DD-6 | must | Use Stat for a key figure on its own, and Count for a tally beside words | Draw a meter for a number with no range: the fill's length means nothing without a max | review |
| DD-7 | must | Announce a change of state in the screen's own polite live region | Make a Meter a live region: a share that updates every few seconds floods the screen reader | review |