Components / feedback
Progress
Sharing Meter's anatomy was deliberate: two bars that look different for no reason is the drift a shared stylesheet prevents.
Summary
How much of a job is done.
| APG pattern | none |
| Built on | native elements |
| Status | stable |
| Since | 0.2.0 |
<Progress label="Uploading" value={3} max={10} valueText="3 of 10 images" />
<Progress label="Uploading" indeterminate />
Anatomy
The same anatomy as Meter, so one stylesheet dresses both shapes while the two stay apart semantically.
| Part | Element | Required |
|---|---|---|
fill | <div> | yes |
header | <div> | no |
label | <span> | no |
track | <div> | yes |
value | <span> | no |
track carries role="progressbar" and the aria-value* set. fill is sized inline.
Properties
| Property | Values | Default | What it does |
|---|---|---|---|
value | number | none | Ignored when indeterminate is set. |
min | number | 0 | The bottom of the range. |
max | number | 100 | The top of the range. |
label | React.ReactNode | none | Drawn beside the bar and used as the control's accessible name. |
valueText | string | none | Overrides the percentage shown and announced — "3 of 10", "2.1 MB of 8 MB". |
indeterminate | boolean | none | The work has no countable steps yet. Drops aria-valuenow, which is what ARIA means by indeterminate, and cycles the bar rather than filling it. |
id | string | none | Wires the label to the bar. One is generated when you omit it, so the accessible name cannot be lost by forgetting. |
States
| State | Expressed as | |
|---|---|---|
| Mixed | data-indeterminate |
Behavior
The fill grows. It never shrinks — if the number can go down, this is the wrong component.
Indeterminate cycles a third of the track across instead of filling.
Accessibility
Indeterminate drops aria-valuenow, which is what the ARIA spec means by indeterminate. It is a state, not a missing value.
The label is the accessible name. Passing none leaves a bar a screen reader can find and cannot describe.
valueText is announced as well as drawn, so the two cannot disagree.
Keyboard
None of its own. It is not focusable and takes no keys.
Roles, states and properties
| Attribute | Set by |
|---|---|
aria-valuemax | set at render |
aria-valuemin | set at render |
role | always progressbar |
Focus
Never takes focus.
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/browser/feedback.spec.mjs
Known gaps
_No upstream requirement is recorded as not applicable._
Appearance
| Token | Used for |
|---|---|
--se-accent | background |
--se-duration-medium | transition |
--se-duration-slow | animation |
--se-ease-standard | animation, transition |
--se-font-code | font-family |
--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 |
Motion
The fill crosses --se-duration-medium when the value changes. Indeterminate cycles over three times --se-duration-slow, forever, and the reduced-motion reset stops it after one pass.
Content
valueText is for anything a percentage says badly. "3 of 10 images" is what a reader wants; "30%" is what the arithmetic produced. Use the unit the reader thinks in — images, megabytes, steps.
Usage
Not a Meter. A meter reports a level that can fall again — disk used, budget spent.
Not a Spinner. The moment you can count the steps, counting them is the kinder answer.
Indeterminate is not a spinner in a different shape. Use it where a bar's shape belongs but the total is not known yet — an upload whose size the server has not reported.
Notes
Sharing Meter's anatomy was deliberate: two bars that look different for no reason is the drift a shared stylesheet prevents.