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.

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:

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

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

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

11. Practice Exercise

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.