Components / data
Meter
Built as a div with role="meter" rather than a native <meter>, because the native element cannot be styled to the contract across the browser floor.
Summary
A measurement inside a known range — storage used, budget spent, sections completed.
| APG pattern | Meter |
| Built on | native elements |
| Status | stable |
| Since | 0.1.0 |
<Meter id="storage" label="Storage" value={3.2} max={10} valueText="3.2 GB of 10 GB" />
<Meter id="sections" label="Sections filled in" value={4} max={7} intent="positive" />
Anatomy
A <div data-se="meter"> with a header and a track. track carries role="meter" and the aria-value* set.
| Part | Element | Required |
|---|---|---|
fill | <div> | yes |
header | <div> | yes |
label | <span> | no |
track | <div> | yes |
value | <span> | yes |
Properties
| Property | Values | Default | What it does |
|---|---|---|---|
value | number | required | The current reading. Clamped to min and max rather than rejected, because a meter that renders nothing tells the reader less than one that renders full. |
min | number | 0 | The bottom of the range. |
max | number | 100 | The top of the range. A meter is meaningless without a known ceiling — that is what separates it from a count. |
label | string | none | Drawn beside the bar and used as the accessible name. |
valueText | string | none | Overrides the computed percentage — use it for "3.2 GB of 10 GB". |
intent | accent · positive · negative · warning | accent | The meaning of the reading, not decoration. Use negative when the level is a problem the reader should act on, never merely because the bar is nearly full. |
id | string | none | Optional. A stable id is generated when omitted; the name never depends on it. |
States
_None. Rest is the only condition it has._
Behavior
The fill tracks the value, up or down.
Accessibility
The value is always written beside the bar. A bar alone cannot be read by a screen reader and cannot be read precisely by anyone at all.
useId supplies the id when none is given, because a label wired to an id the consumer had to remember is an accessible name the consumer will forget.
Keyboard
None of its own. It is not focusable and takes no keys.
Roles, states and properties
| Attribute | Set by |
|---|---|
aria-label | set at render |
aria-labelledby | set at render |
aria-valuemax | set at render |
aria-valuemin | set at render |
aria-valuenow | set at render |
aria-valuetext | set at render |
role | always meter |
Focus
Never takes focus. It reports a value and offers no action.
Screen reader
Not recorded as verified. Stage 4 of the readiness ladder — driving each component with VoiceOver and NVDA — is unstarted across the package, and no component should claim otherwise until docs/journal/ records the session that did it.
Contrast and target size
npm run check:contrast audits every color pair this component uses across all four skins, light and dark, and fails the build on a shortfall. Two waivers are on the record in docs/audit/DEFERRED.md.
It sets no target size of its own; anything interactive inside it brings its own.
Tested
test/apg/partials-sweep.test.jsx
Known gaps
_No upstream requirement is recorded as not applicable._
Appearance
| Token | Used for |
|---|---|
--se-accent | intent |
--se-duration-medium | transition |
--se-ease-standard | transition |
--se-font-code | font-family |
--se-negative | intent |
--se-positive | intent |
--se-radius-pill | border-radius |
--se-space-2 | block-size, gap |
--se-space-3 | gap |
--se-surface-sunk | background |
--se-text | color |
--se-text-muted | color |
--se-text-sm | font-size |
--se-warning | intent |
Shared with Progress, so the two cannot drift apart visually while staying apart semantically.
Motion
The fill crosses --se-duration-medium when the value changes.
Content
Pass valueText whenever the raw units mean more than a percentage. 3.2 GB of 10 GB is what a reader wants.
Usage
Not a progress bar. A meter reports a level that can fall again; progress only ever fills. If the number can go down, this is the right component.
intent is for the meaning of the reading, not decoration. negative when the level is a problem the reader should act on — never merely because the bar is nearly full.
Notes
Built as a div with role="meter" rather than a native <meter>, because the native element cannot be styled to the contract across the browser floor.