ThisCalculator

Everyday

Accessible Bootstrap Progress Bars: v5 Guide

Updated · Standard formula, shown below

Accessible Bootstrap Progress Bars: v5 Guide

Bootstrap 5 progress bars can be made accessible by adding the role="progressbar", aria-valuenow, aria-valuemin, and aria-valuemax attributes, plus a visually hidden label. This guide explains the exact markup, common pitfalls, and how to test your implementation.

Why Accessibility Matters for Progress Bars

Progress bars are inherently visual. A sighted user sees a colored bar filling a track, but a screen reader user only hears the element’s name and value. Without proper ARIA attributes, a progress bar is announced as an unlabeled graphic or, worse, ignored entirely. The Web Content Accessibility Guidelines (WCAG) 2.1 Success Criterion 1.1.1 (Non-text Content) and 4.1.2 (Name, Role, Value) directly apply. Bootstrap 5’s default .progress component does not include ARIA attributes automatically—you must add them yourself. This is a common misconception; many assume Bootstrap handles it, but the documentation explicitly shows the attributes in examples, meaning they are the developer’s responsibility.

The Correct Bootstrap 5 Markup

Here is the minimal accessible progress bar, using Bootstrap 5’s classes and the required ARIA:

<div class="progress" role="progressbar" aria-label="Upload progress" aria-valuenow="70" aria-valuemin="0" aria-valuemax="100">
  <div class="progress-bar" style="width:70%">70%</div>
</div>

Key points:

  • Role and aria-* on the wrapper: The role="progressbar" and the three aria-valuenow/min/max attributes go on the outer .progress div, not the inner bar. This is what screen readers announce.
  • Label: Use aria-label (as above) if there is no visible text. If a visible label exists (e.g., a heading above), use aria-labelledby pointing to its ID.
  • Visible text: The inner .progress-bar can contain text like “70%â€�. This is fine, but it is not the primary accessible name—the ARIA attributes take precedence.
  • Width: The inline style="width:70%" controls the visual fill. Keep it in sync with aria-valuenow.

Dynamic Updates and Screen Reader Behavior

When a progress bar updates (e.g., during a file upload), you must update both the style width and the aria-valuenow attribute via JavaScript. Screen readers do not automatically re-announce changes unless you use a live region. Bootstrap does not provide a built-in live region for progress bars. The common solution is to add aria-live="polite" to the outer .progress element. However, be cautious: aria-live on a progressbar role can cause excessive announcements in some screen readers. A better practice is to place a visually hidden span with aria-live="polite" that updates with the percentage text. Example:

<div class="progress" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" aria-label="Upload progress">
  <div class="progress-bar" style="width:0%"></div>
</div>
<span class="visually-hidden" aria-live="polite" id="progress-live">0%</span>

Then in JavaScript, update aria-valuenow, the width, and the text of #progress-live together. This gives screen reader users a polite announcement without overwhelming them.

Common Mistakes and How to Avoid Them

  • Putting ARIA on the inner bar: The inner .progress-bar is a child element; the role must be on the container that represents the whole widget.
  • Forgetting aria-valuenow for indeterminate bars: For an indeterminate progress bar (no known percentage), omit aria-valuenow and add aria-valuetext="loading" or use the .progress-bar-striped class with aria-label="Loading". Do not set aria-valuenow to a fake value.
  • Using aria-valuenow outside 0–100: If your progress is based on a different scale (e.g., 0–10), set aria-valuemin and aria-valuemax accordingly. The attribute does not force 0–100; it follows your min/max.
  • Not testing with a real screen reader: Browser dev tools cannot simulate screen reader announcements. Use NVDA (Windows) or VoiceOver (macOS) to verify.

Testing Your Progress Bar

Automated tools like axe or Lighthouse can catch missing ARIA attributes, but they cannot verify the announcement order. Manual testing steps:

  1. Open the page with NVDA or VoiceOver.
  2. Navigate to the progress bar using the Tab key or the virtual cursor.
  3. Listen for the label, the role, and the value. For example: “Upload progress, progress bar, 70%�.
  4. If the bar updates, check that the live region announces the new percentage without requiring user interaction.
  5. Test with a keyboard only: ensure the bar is not a tab stop (it should not be focusable unless it has interactive controls).

If the bar is purely informational, it should be hidden from the tab order. If it has controls (e.g., a cancel button), those controls are focusable, not the bar itself.

Bootstrap 5 vs. Other Versions

Bootstrap 4 had the same ARIA requirements; nothing changed in v5 for the core progress bar. The main difference is that v5 dropped jQuery and uses more modern CSS variables, but the accessibility pattern is identical. If you are upgrading, your existing ARIA attributes will continue to work. However, v5’s .visually-hidden class replaces v4’s .sr-only—use the new class for the live region. Also note that v5’s progress bar supports height via CSS variables, but this does not affect accessibility.

Alternatives to Bootstrap’s Progress Bar

If you need a more accessible or customizable progress bar, consider:

  • Native HTML <progress> element: Browsers provide built-in accessibility. Example: <progress max="100" value="70">70%</progress>. You can style it with CSS, but cross-browser styling is more limited than Bootstrap’s.
  • ARIA authoring practices: The W3C’s APG pattern for progressbar is essentially what Bootstrap uses, but you can implement it from scratch for full control.
  • Third-party libraries: Many exist, but they often require extra CSS to match Bootstrap’s look. Stick with Bootstrap unless you have a specific need.

For most projects, Bootstrap’s progress bar with the ARIA attributes described above is sufficient and accessible.

Frequently Asked Questions

Do I really need to add ARIA attributes to Bootstrap progress bars?

Yes. Bootstrap’s CSS does not add them automatically. Without role="progressbar" and the aria-valuenow, aria-valuemin, aria-valuemax attributes, screen readers will not identify the element as a progress bar. They may read the text inside, but not the dynamic value or the role.

What is the difference between aria-valuenow and the visible text?

aria-valuenow is the machine-readable value that assistive technologies use. The visible text is for sighted users. They should match, but if they differ (e.g., you show “Step 3 of 5� while aria-valuenow is 60), screen readers will announce aria-valuenow (60) unless you use aria-valuetext to override. Use aria-valuetext to provide a human-readable equivalent like “Step 3 of 5�.

How do I make an indeterminate progress bar accessible?

For an indeterminate bar (no known percentage), omit aria-valuenow and set aria-valuemin="0" and aria-valuemax="100" (or any range). Add aria-valuetext="Loading..." or use aria-label="Loading". The role="progressbar" still applies. Bootstrap’s striped animation class works fine with this.

Should I use aria-live on the progress bar itself?

Generally, no. Adding aria-live="polite" directly to the role="progressbar" element can cause screen readers to announce every change, which may be too noisy. Instead, use a separate visually hidden live region that you update with the percentage text. This gives you control over when and how often announcements occur.

Can I use the HTML5 <progress> element instead of Bootstrap’s?

Yes. The native <progress> element is accessible by default. You can style it with CSS to look like Bootstrap’s bar, but it may not match exactly across browsers. If you need the exact Bootstrap look, stick with the div-based approach and add the ARIA attributes.

Does Bootstrap 5’s progress bar work with dark mode?

Yes, Bootstrap 5 supports dark mode via CSS variables, and the progress bar adapts. Accessibility-wise, ensure the contrast between the bar and the track meets WCAG AA (at least 3:1 for non-text contrast). Bootstrap’s default colors may not meet this in all themes—test with a contrast checker.

Related

Method: the standard formula for this calculation, rounded as each result states. See how the calculators work or report an error.