When we build interfaces that need to show progress, especially step-by-step forms, which is where I most use <progress>, I always opt for the native HTML5 progress bar first.
The HTML 5 progress bar is lightweight, accessible, easy to style, and doesn't need external libraries.
In this article, I'll explain everything you need to know to master it: attributes, states, CSS, JavaScript, accessibility, and a complete ready-to-use example.
What is an HTML5 Progress Bar and what is it for?
A progress bar is a visual indicator that shows how much of a task has been completed. The good thing about the <progress> element is that HTML5 includes it as a native component to represent determinate or indeterminate progress.
The function of the progress element or tag is to indicate the completion status of a task.
<progress> Tag and Main Purpose
Its syntax is as follows:
<progress></progress> We see that, like most tags in HTML, it features a starting tag <progress> and a closing tag </progress>.
Since it's a progress bar, let's add some progress:
<progress value="50" max="100"></progress>This represents that the task is 50% complete.
When to use progress bars (and when not to)
They are useful for:
- file uploads and downloads.
- waiting processes.
- steps in a form.
- background tasks.
Attributes of the (tag) progress tag
Apart from the global attributes for all tags (class, id, etc.) and unlike the <meter> tag, it only has two attributes according to the W3C:
value:Specifies how much of the task has been completed; more specifically; it is a floating-point value that represents the current value of the task. This value must be between 0.0 and the value ofmax, or 1.0 if themaxattribute is not present.max:Specifies how much of this task is required in total. In other words, it indicates a value that represents the maximum of the task; and therefore the maximum possible value for thevalueattribute; this value must be greater than 0.0, if not specified the default is 1.0.
States of the progress bar tag
The progress bar tag can be in two states: determinate and indeterminate.
State: Determinate Progress Bar
For the progress bar to be in the "determinate" state, the value attribute must be present.
<progress value="0.5"></progress> State: Indeterminate Progress Bar
For the progress bar to be in the "Indeterminate" state, the value attribute must not be present; or simply remove this attribute.
The reason for this state; imagine we have a progress bar tag on our page and we lose the connection with the host; our JavaScript code should detect this possible state and remove the value attribute, to indicate to the user that there was a problem with the connection.
<progress></progress> General Rules for the Progress Bar (summary)
- All attributes mentioned above are floating-point numbers greater than 0.0.
- The
maxattribute must be greater than 0.0. - According to the definitions of each attribute, the following expressions are true:
0.0 <= value <= 1.0(ifmaxis not specified).0.0 <= value <= max(ifmaxis specified).
Styles of the (tag) progress tag
| Pseudo-classes | Description |
|---|---|
-webkit-progress-bar / -moz-progress-bar | Defines a style for the container of the progress tag. |
-webkit-progress-value | Defines a style for the value of the progress tag. |
Example 1
This first experiment shows the first case presented in the "general rules" section; in which the max attribute is not present.
In addition to this, we will use a script to vary the value of the progress tag over a determined time and observe its behavior over time.
As we can see; since the max attribute is not present; it takes its default value; that is; 1.0.
<progress id="progress1" value="0" ></progress> To see the complete code for the experiment, click here.
Example 2
This example shows all the attributes presented previously; basically the value attribute and the max attribute.
With the help of the previous script, let's see its behavior:
<progress id="progress2" max="100" value="0" ></progress> To see the complete code for the experiment, click here.
Example 3
We can customize the progress tag in various ways; changing the border-radius or the background, the padding among many others.
progress {
display:block;
-webkit-appearance: none;
}
progress::-webkit-progress-bar {
background: black;
border-radius: 50px;
padding: 2px;
}
progress::-moz-progress-bar {
background: black;
border-radius: 50px;
padding: 2px;
}
progress::-webkit-progress-value {
border-radius: 50px;
background:orange;
}To see the complete code for the experiment, click here.
<progress> Syntax: value and max attributes explained
How the determinate state works
A bar is "determinate" when it includes value.
Example at 40%:
<progress value="40" max="100"></progress>If you don't add max, its default value is 1, and you can use decimals:
<progress value="0.4"></progress>How the indeterminate state works
If you remove the value attribute, the browser shows an unknown progress animation.
<progress></progress>I use it when a process depends on an external server and I don't know how much is left. In fact, during a development I had to temporarily remove value to indicate that the system was waiting for a response... and it worked perfectly for the user to understand that there was no failure yet.
Good practices to avoid common errors
- Do not use negative values.
- value must never exceed max.
- If you use decimals, respect the standard: between 0 and 1 when you don't define max.
Styling the progress bar with CSS
The native style works, but it is usually basic. To customize, I first reset the appearance:
progress {
-webkit-appearance: none;
appearance: none;
width: 100%;
height: 20px;
}WebKit and Firefox Pseudo-elements
For Chrome / Safari:
progress::-webkit-progress-bar {
background: #eee;
border-radius: 6px;
}
progress::-webkit-progress-value {
background: #4caf50;
border-radius: 6px;
}For Firefox:
progress::-moz-progress-bar {
background: #4caf50;
border-radius: 6px;
}Custom colors, sizes, and styles
You can create bars:
- Round.
- With gradients.
- With animations.
- Ultra-thin, like "YouTube".
For example:
progress[value]::-webkit-progress-value {
transition: width .4s ease;
}That smooths the progress and improves the perception of fluidity.
Updating the Progress Bar with JavaScript
Dynamically changing value
const bar = document.querySelector('progress');
bar.value = 70;Animating the progress bar
Ideal for background processes:
setInterval(() => {
if (bar.value < bar.max) bar.value++;
}, 100);Example: real-time updating bar
In my step-by-step forms, I update the bar when the user completes a section:
function setStepProgress(step, totalSteps) {
const bar = document.getElementById('form-progress');
bar.value = step;
bar.max = totalSteps;
}That simple fragment makes the user "feel" like they are progressing. The difference in abandonment is brutal.
Progress Bar in step-by-step forms (multi-step forms)
This is the reason I use <progress> almost daily. When forms have 3, 4, or 5 steps, showing progress increases the completion rate.
How to calculate progress by steps
If you have 4 steps:
- Step 1 = value 1
- Step 2 = value 2
- Step 3 = value 3
- Step 4 = value 4
And max = 4.
Practical example: progress bar for multi-step form
I'll show you a complete example where you can use a step-by-step form with the progress bar that includes labels to display the step and the bar; furthermore, an example JavaScript is defined to move the bar's state:
<progress id="form-progress" value="1" max="4"></progress>
<div class="step step-1">Contenido del paso 1…</div>
<div class="step step-2" style="display:none">Paso 2…</div>
<div class="step step-3" style="display:none">Paso 3…</div>
<div class="step step-4" style="display:none">Paso 4…</div>
<button id="next">Siguiente</button>
<script>
let step = 1;
document.getElementById('next').addEventListener('click', () => {
const totalSteps = 4;
if (step < totalSteps) {
document.querySelector('.step-' + step).style.display = 'none';
step++;
document.querySelector('.step-' + step).style.display = 'block';
setStepProgress(step, totalSteps);
}
});
function setStepProgress(step, total) {
const bar = document.getElementById('form-progress');
bar.value = step;
bar.max = total;
}
</script>UX tips based on real experience
- Showing the current step / total increases clarity.
- Bars that advance smoothly generate more confidence.
- I noticed that when I used a bar without a percentage, users progressed faster: the "sense of progress" is enough.
Accessibility: how to make a Progress Bar accessible
Add ARIA attributes:
<progress value="40" max="100"
aria-valuenow="40"
aria-valuemin="0"
aria-valuemax="100">
40%
</progress>Quick tips:
- Always use a <label> tag.
- Add alternative text inside the element.
- Maintain good contrast between the bar and the background.
Cross-browser compatibility
- Chrome, Firefox, Edge, and Safari support <progress>.
- Visual differences exist, but you can level them out with CSS.
- It works well on mobile, but it's advisable to give it more height to make it more visible.
Complete Example: Animated HTML5 Progress Bar
In this example, we will see how we can simulate the progress bar update using JavaScript:
<label for="demo-progress">Progreso:</label>
<progress id="demo-progress" value="30" max="100"></progress>
<script>
function simulate() {
const bar = document.getElementById('demo-progress');
if (bar.value < bar.max) {
bar.value += 1;
requestAnimationFrame(simulate);
}
}
simulate();
</script>
<style>
progress {
width: 100%;
height: 20px;
-webkit-appearance: none;
appearance: none;
border-radius: 8px;
}
progress::-webkit-progress-bar {
background: #eee;
border-radius: 8px;
}
progress::-webkit-progress-value {
background: #ff8a00;
border-radius: 8px;
transition: width .3s ease;
}
progress::-moz-progress-bar {
background: #ff8a00;
border-radius: 8px;
}
</style>Frequently Asked Questions
- How does the <progress> tag work?
- It visually shows the progress of a task using the value and max attributes.
- What happens if I don't put value?
- The bar enters indeterminate mode, showing constant movement.
- How do I update the bar with JavaScript?
- Modify its .value property.
- How do you make a bar for a multi-step form?
- Give value the current step number and max the total number of steps.
- How do I make it accessible?
- Use ARIA attributes: aria-valuenow, aria-valuemin, aria-valuemax.
- How do I style it to look the same in all browsers?
- Use pseudo-elements ::-webkit-progress-* and ::-moz-progress-bar.
Conclusions
In this post, you can see several complete examples and use cases so that you can use the progress bar, which, as its name indicates, is extremely useful for displaying tasks that are being performed and showing the status.
I agree to receive announcements of interest about this Blog.
Learn how to use the HTML5 Progress Bar with