A download bar moves from 0% to 100% while a file transfers. A three step signup form shows a bar that fills in as the user moves forward. In both cases, a task is actively running, mechanically progressing toward a final state known in advance. It is neither a fixed measurement nor a decorative animation: it is a status that keeps changing, and deserves to be announced as such.
The <progress> tag represents exactly that situation: a task moving toward completion, never a static value.
Definition
<progress> indicates how far a task has moved toward completion. Unlike <meter>, it never compares a value against quality thresholds: it simply announces a fraction completed out of a total, and that fraction only makes sense because it grows over time or with each step cleared.
The browser gives it a dedicated accessibility role, announced to screen readers with the current percentage, with no extra ARIA attribute required.
The value and max attributes
Two attributes are enough to describe the progress. Leaving them out radically changes both the rendering and the meaning of the tag.
| Attribute | Role |
|---|---|
value | The amount already completed |
max | The total to reach, 1 by default if absent |
No min attribute: unlike <meter>, <progress> always starts at zero. A task has no negotiable starting point, only a finishing line.
Concrete example
Here is a progress bar for a file download, updated by script as bytes arrive.
<label for="dl">Download in progress</label>
<progress id="dl" value="70" max="100">70%</progress>The text between the tags, here 70%, only shows in browsers unable to render <progress>, but is still worth writing out for that fallback case.
The indeterminate bar
Leaving out the value attribute entirely turns the bar into its indeterminate version: an animation showing that a task is running without being able to put a number on it. That is the typical case for a search with an unpredictable duration, or a server process whose total size is not yet known.
<progress>Loading</progress>As soon as an estimate becomes available, adding value and max switches the bar into determinate mode. Many sites start indeterminate while waiting for the first measurement, then switch to a numbered progress once it arrives.
Difference with <meter>
The question to ask is always the same: does the value move toward completion, or does it describe a measured state? The steps of a checkout flow, a file upload or an app installing all move toward an end: that is <progress>. A battery level or a fill rate are states, with no notion of completion: that is <meter>.
A multi step form is the most common source of confusion. Some developers reach for <meter> there because the bar looks visually identical to a gauge, when the correct semantics really are <progress>: each step brings the user closer to completion, it does not measure a stable state.
Frequently asked questions
progress bar?Yes, and <output> fits that calculated result well: the progress tag carries the advancement, while a separate output, recalculated on every update, shows the estimated remaining time as readable text.
progress work without JavaScript?The visual rendering shows up without any script, but its value stays fixed at whatever was written in the HTML when the page loaded. Actually moving the bar forward during a task requires script that updates the value attribute at regular intervals or on each relevant event.
progress be used for a purely decorative loading animation?No, if no real task is actually running in the background, a plain decorative element marked aria-hidden="true" is enough. Reserving <progress> for cases where real progress exists avoids announcing a status to assistive technology that matches nothing concrete.