ARIA Progressbar Must Have an Accessible Name: How to Fix It

No Comments
Aria progressbar must have an accessible name: how to fix it

What this check flags

This rule fires when an element with role="progressbar" has no accessible name. A screen reader reaches it and announces “progress bar, 40 percent” — forty percent of what? Upload? Checkout? Quiz score? Without a name the number is meaningless. Progress indicators are usually the feedback for a slow operation, so an unnamed one leaves assistive-tech users guessing whether the thing they just started is even working. It won’t move rankings, but it’s a clean, cheap Lighthouse win and a genuine usability fix.

The reason this one stings is timing. A progressbar shows up precisely when the user is anxious — they’ve submitted a form, kicked off a big file upload, or triggered a report that takes a while. A sighted user glances at the caption and the moving bar and relaxes: it’s working, give it a moment. Strip the name and a screen-reader user gets a bare percentage floating in space with no idea what it’s measuring. Did the upload start, or is this some other counter? The single word of context a name provides is the difference between reassurance and a page reload that cancels the very operation they were waiting on.

A real failing snippet, and the fix

A typical upload widget sets the value attributes but never names the bar:

<!-- FAILS: progressbar with value but no name -->
<div role="progressbar"
     aria-valuenow="40"
     aria-valuemin="0"
     aria-valuemax="100"></div>

The value states are fine; what’s missing is a label. If there’s visible caption text, wire it up with aria-labelledby; if not, add an aria-label that says what’s progressing:

<!-- PASSES: the bar now names what it's tracking -->
<span id="upload-lbl">Uploading photos</span>
<div role="progressbar"
     aria-labelledby="upload-lbl"
     aria-valuenow="40"
     aria-valuemin="0"
     aria-valuemax="100"></div>

<!-- or, with no visible caption -->
<div role="progressbar"
     aria-label="Uploading photos"
     aria-valuenow="40" aria-valuemin="0" aria-valuemax="100"></div>

Best of all, the native <progress> element paired with a <label> gives you the role, the value semantics, and the name without a single ARIA attribute. Reach for it first.

Name vs. value: two different jobs

People conflate the label with the percentage. They’re separate concerns — the name says what it is, the value states say how far along it is. A progressbar needs both to announce cleanly.

AttributeAnswersExample
aria-label / aria-labelledbyWhat is this bar for?“Uploading photos”
aria-valuenowWhere is it right now?40
aria-valuemin / aria-valuemaxWhat’s the range?0100
aria-valuetextA human-readable value (optional)“Step 2 of 5”

For an indeterminate spinner where you can’t report a percentage, omit aria-valuenow entirely — but the accessible name is still required.

How to detect it

  1. axe DevTools: the “ARIA progressbar must have an accessible name” violation lists each unnamed bar and points to the node in the DOM.
  2. Lighthouse: run the Accessibility audit; the check sits in the ARIA group with the failing progressbars enumerated beneath it.
  3. ARIA DevTools / accessibility tree: select the progressbar in the Accessibility panel and read the computed Name. Empty means it still fails, regardless of what the DOM looks like.

How to fix it

  1. Locate the flagged element and confirm it really needs to be a progressbar (a static bar that never updates might not).
  2. If a visible caption exists, add aria-labelledby referencing its id.
  3. Otherwise add a short, specific aria-label describing the operation.
  4. Keep the value attributes accurate — a name without a moving aria-valuenow tells only half the story.
  5. Consider swapping to native <progress> with a <label>.
  6. Re-scan and confirm the computed name is populated.

One design decision that quietly prevents this bug: if the bar has a visible caption anyway — “Uploading photos… 40%” — wire that existing text in with aria-labelledby instead of duplicating it in an aria-label. You get one source of truth, so when the copy changes the accessible name changes with it, and there’s no risk of the visible caption and the announced name drifting apart over time. Duplicated label strings are how a “Saving draft” caption ends up reading as “Uploading photos” six months later.

If your value attributes are also out of range (a valuenow above valuemax, for instance), that’s a separate failure — see ARIA attributes must conform to valid values.

FAQ

My progressbar is decorative — do I still need a name?

If it conveys no real status, it probably shouldn’t have role="progressbar" at all. Remove the role, or mark the wrapper aria-hidden="true" if it’s purely visual. Once it declares the role, a name is mandatory.

Can the percentage text inside the bar serve as the name?

No — “40%” is a value, not a name. Even if that text is read, it doesn’t tell anyone what the bar measures. Add an explicit label.

What about an indeterminate loading bar with no known duration?

Drop aria-valuenow so it’s announced as indeterminate, but keep the accessible name (e.g. “Loading results”). The name requirement doesn’t go away just because the value is unknown.

How is this different from the input-field name check?

Same underlying naming mechanics, different role. The input-field rule covers textbox, combobox, and friends — see ARIA input fields must have an accessible name. This one is scoped to progressbar.

Should I also announce progress changes as they happen?

Often, yes — and it’s a separate concern from naming. A named progressbar tells a screen reader what the control is, but by default the reader won’t re-announce every tick as the value climbs. If it matters that the user hears updates (a long export, say), pair the bar with a polite live region, or let the platform’s native <progress> handling take care of it. Just don’t make it chatty: announcing every single percent from 1 to 100 is its own accessibility problem. Name it first, then decide whether live updates earn their keep.

Claude Vincent is a technical SEO consultant focused on crawlability, rendering, and AI-search visibility. He writes the field guides and case studies at SEO ProCheck, with a bias toward the durable, unglamorous work that decides whether search engines and AI answer engines can actually read and cite a site.

About SEO ProCheck

Technical SEO consulting and GEO strategy with 20 years of enterprise experience. Case studies, resources, and tools for search and AI visibility.

Work With Me

Technical SEO audits, GEO strategy, site migrations, and international SEO. Hourly consulting for teams who need hands-on support, not just reports.

Subscribe to our newsletter!

More from our blog