HTML progress and meter: Using <progress> and <meter>
HTML provides two related elements for showing measured values: progress for task completion and meter for a value within a known range. They look similar, but they describe different kinds of information, which matters for accessibility, semantics, and validation.
Quick answer: Use <progress> for something that is actively being completed, such as a file upload or a setup task. Use <meter> for a measurement that has a meaning inside a fixed range, such as disk usage, temperature, or a rating.
Difficulty: Beginner
You'll understand this better if you know: basic HTML elements, attributes like value and max, and the difference between content that describes a state versus content that shows a measurement.
1. What Are progress and meter?
<progress> represents how far a task has advanced toward completion. <meter> represents a scalar measurement within a known range, where the value is meaningful relative to thresholds.
- <progress> is for completion state.
- <meter> is for a measured quantity.
- Both are semantic HTML elements, so they communicate meaning to browsers and assistive technologies.
- Neither element is meant to replace a custom visual component when you need advanced styling or animation.
2. Why progress and meter Matter
These elements make your pages more descriptive and easier to understand for users, screen readers, and browsers. Instead of using a generic <div> and hoping users infer the meaning, you can tell the browser exactly what the number means.
That semantic meaning improves:
- Accessibility, because assistive technology can announce the value correctly.
- Validation, because the browser knows which attributes belong on which element.
- Maintainability, because your HTML clearly distinguishes progress from measurement.
3. Basic Syntax or Core Idea
progress
Use <progress> with a current value and, usually, a maximum value. If the task has started but the amount completed is unknown, omit the value attribute to create an indeterminate progress indicator.
The simplest form looks like this:
<label for="upload">Upload progress</label>
<progress id="upload" value="35" max="100">35%</progress>
The value tells the browser how much is complete, and max sets the total. The text inside the element acts as fallback content for older browsers or plain-text contexts.
meter
Use <meter> when the number has a known range and meaning, such as a rating or usage level. You can define the minimum, maximum, ideal, and threshold values.
A minimal example looks like this:
<label for="disk">Disk usage</label>
<meter id="disk" value="0.72" min="0" max="1">72%</meter>
Here, the value is part of a scale from 0 to 1, and the visible text helps users interpret the number even if the element is not rendered as a gauge.
4. Step-by-Step Examples
Example 1: File upload progress
Use <progress> when a task is moving toward completion and the value changes over time.
<form action="/upload" method="post" enctype="multipart/form-data">
<label for="file">Select a file</label>
<input type="file" id="file" name="file">
<progress value="48" max="100">48%</progress>
</form>
This says the upload is 48 percent complete. In a real app, the value would update as the upload proceeds.
Example 2: Indeterminate task
When work is happening but the completion amount is not known, leave out value.
<p>Preparing your report...</p>
<progress max="100">Loading</progress>
Browsers usually render this as an indeterminate state. The fallback text can still give users context if the visual control is not displayed.
Example 3: Rating with meter
Use <meter> for a review score or rating when there is a real scale behind the number.
<p>User satisfaction</p>
<meter min="0" max="10" low="4" high="8" optimum="10" value="7.5">7.5 out of 10</meter>
The threshold attributes help communicate whether the value is considered low, acceptable, or ideal.
Example 4: Compare task completion and current usage
These two elements can appear on the same page, but they should describe different kinds of information.
<section>
<h2>Backup status</h2>
<p>Files uploaded</p>
<progress value="12" max="20">12 of 20</progress>
<p>Storage used</p>
<meter min="0" max="100" value="68">68%</meter>
</section>
This example shows how completion and measurement can coexist without meaning the same thing.
5. Practical Use Cases
- <progress> for file uploads, downloads, installations, and import jobs.
- <progress> for multi-step forms or onboarding where completion percentage is meaningful.
- <meter> for disk space usage, battery-like readings, test scores, and ratings.
- <meter> for values that sit inside a known scale, such as CPU load or satisfaction score.
- Both elements are useful when the number is part of the content, not just decoration.
6. Common Mistakes
Mistake 1: Using progress for a static measurement
<progress> describes completion, not just any value with a percentage. If you are showing a rating or usage level, it is usually the wrong element.
Problem: This markup says a disk usage value is a task in progress, which gives the wrong semantic meaning to users and assistive technology.
<label for="storage">Storage used</label>
<progress id="storage" value="68" max="100">68%</progress>
Fix: Use <meter> for a value that belongs to a range rather than a task.
<label for="storage">Storage used</label>
<meter id="storage" min="0" max="100" value="68">68%</meter>
The corrected version works because it matches the element to the meaning of the data.
Mistake 2: Omitting max when the value should be bounded
For <progress>, the range matters. If you leave out max and then treat the number as a percentage anyway, your markup becomes harder to interpret correctly.
Problem: This example shows a partial task, but the maximum is not explicit, so readers cannot tell what the value means.
<progress value="35">35%</progress>
Fix: Provide the maximum so the completion ratio is clear.
<progress value="35" max="100">35%</progress>
The fixed version makes the relationship between current progress and the total explicit.
Mistake 3: Using meter without a meaningful range
<meter> only makes sense when the value is measured against a known scale. If there is no real minimum and maximum, the gauge becomes arbitrary.
Problem: This uses <meter> for a status message where no valid measurement range exists.
<meter value="3">Processing</meter>
Fix: Use plain text or a <progress> element if a task is underway.
<p>Processing</p>
<progress value="3" max="10">3 of 10</progress>
The corrected version works because it uses a semantic element that matches the information being shown.
7. Best Practices
Practice 1: Always provide visible text or an accessible label
Users should not have to guess what the bar or gauge refers to. A label nearby or associated with the element helps everyone understand the value.
<label for="download">Download progress</label>
<progress id="download" value="80" max="100">80%</progress>
This works well because the purpose of the value is clear even if the visual styling is minimal.
Practice 2: Use meter thresholds to communicate meaning
<meter> can express more than a number. Thresholds such as low, high, and optimum let the browser understand whether the value is good or bad.
<meter min="0" max="100" low="40" high="80" optimum="90" value="65">65%</meter>
This is better than a plain percentage because it adds context to the number.
Practice 3: Keep the fallback text meaningful
The text inside these elements is not just decorative. It can help in non-visual contexts and should describe the value clearly.
<progress value="3" max="5">3 of 5 steps complete</progress>
This approach is helpful because the fallback text still makes sense when the element is not rendered as a native control.
8. Limitations and Edge Cases
- Browser styling varies, so the default appearance may differ across platforms.
- <progress> does not automatically update itself; the value must be changed by your application.
- <meter> is not a generic gauge for any number. It depends on a meaningful range.
- These elements are semantic, but they are not full UI systems. If you need custom animation or rich interaction, you may need additional markup around them.
- Do not rely on color alone to communicate state; users need labels or text too.
9. Practical Mini Project
Here is a small, complete example for a course dashboard that uses both elements correctly: <progress> shows lesson completion, and <meter> shows quiz score.
<section aria-labelledby="course-status-title">
<h2 id="course-status-title">Course status</h2>
<div>
<label for="lessons">Lessons completed</label>
<progress id="lessons" value="6" max="10">6 of 10 lessons complete</progress>
</div>
<div>
<p>Latest quiz score</p>
<meter min="0" max="100" low="50" high="85" optimum="100" value="88">88 out of 100</meter>
</div>
</section>
This example is complete, semantic, and easy to read. It also keeps the labels close to the values, which improves accessibility and clarity.
10. Key Points
- <progress> is for task completion.
- <meter> is for measurements inside a range.
- Use labels so users know what the number means.
- Provide fallback text that still makes sense without the visual control.
- Choose the element based on semantics, not just appearance.
11. Practice Exercise
- Create a status card for an online backup tool.
- Show upload completion with <progress>.
- Show remaining storage with <meter>.
- Add clear labels so each value is understandable on its own.
Expected output: A small HTML section that includes one progress indicator for the backup job and one meter for storage usage.
Hint: Ask yourself whether the number describes work being completed or a measured value in a range.
<section aria-labelledby="backup-title">
<h2 id="backup-title">Backup status</h2>
<label for="backup-progress">Backup progress</label>
<progress id="backup-progress" value="4" max="8">4 of 8 files backed up</progress>
<label for="storage-meter">Storage used</label>
<meter id="storage-meter" min="0" max="100" low="70" high="90" value="76">76%</meter>
</section>
The solution uses each element for its intended semantic purpose, which makes the result clearer and more accessible.
12. Final Summary
<progress> and <meter> look similar, but they describe different ideas. Use <progress> when the user is waiting for a task to finish, and use <meter> when you are presenting a value inside a known range.
Choosing the right element gives your HTML better meaning, improves accessibility, and makes your intent obvious to other developers. When in doubt, ask whether the number is about completion or measurement — that question usually tells you which element fits.
As a next step, compare these elements with ARIA-based custom progress indicators so you can recognize when native HTML is enough and when a custom widget is necessary.