Progress
Progress — how far along a task is.
Examples
Uploading photos — 30%
<p id="upload-status" aria-live="polite">Uploading photos — 30%</p>
<progress class="progress" aria-labelledby="upload-status" max="100" value="30"></progress>The sentence above the bar does three jobs at once: it names the bar, it shows the number the bar cannot, and it is the live region that announces the change.
<progress> is not a live region and a bar that fills silently tells a screen reader user nothing.
Preparing your export…
<p id="export-status" aria-live="polite">Preparing your export…</p>
<progress class="progress" aria-labelledby="export-status"></progress>No value attribute at all — that is what makes it indeterminate. Under prefers-reduced-motion the animation stops outright rather than speeding up: an infinite 0.01ms animation is a busy loop, not a stilled one.
Tokens 7
Level 2, declared on .progress itself. Set any of them on that selector to restyle this component without touching the skin.
| Token | Default |
|---|---|
| --progress-block-size | 1rem |
| --progress-indeterminate-duration | var(--duration-slower) |
| --progress-radius | var(--radius-full) |
| --progress-track-border-color | var(--color-border) |
| --progress-track-color | var(--color-surface-sunken) |
| --progress-transition-duration | var(--duration-normal) |
| --progress-value-color | var(--color-primary) |
Variants and states
Variants
.progress-danger.progress-lg.progress-sm.progress-success.progress-warning
State it reads
None.
Before you ship it
What you have to do 1 requirements
- Give it a name.
<progress>is a labelable element, so<label for>does compute a name in current engines, but a progress bar is rarely next to a form label —aria-labelledbypointing at the heading or sentence that already describes the task is usually the honest markup, andaria-labelis the fallback when no such text exists. An unnamed progress bar is announced as a bare percentage.<progress>is not a live region. The bar filling from 10% to 90% is silent: nothing is announced unless the user's cursor happens to be on it. For a long-running task, put a sentence next to the bar and mark thataria-live="polite"— "Uploading, 30%" — and update it in coarse steps (every 10%, or on state changes) rather than on every frame, which floods the speech queue. When the task ends, say so in the same region; a bar that reaches 100% announces nothing either. The percentage is not visible. This component paints a bar, not a number. If the figure matters, write it in your own markup next to the bar. A CSS-generated number would be unselectable and, on<progress>, unrenderable —::before/::afterdo not apply to a replaced element.
src/css/components/progress.css · npx mostlycss add progress