squirrelscan
GitHub

Accessible name for a progress bar and role=progressbar

A progress bar with no name announces a percentage and nothing else. squirrel checks native progress elements and role=progressbar.

What a progress bar is

<progress> shows how far a task has got: an upload, an install, a multi-step form. ARIA’s role="progressbar" says the same thing about a custom widget.

The text between the tags is fallback content for browsers without support, not a name. Without aria-label, aria-labelledby, title or a <label>, a screen reader announces “progress bar, 50 percent” and leaves the user to guess what is at 50 percent.

What squirrel checks

One check, aria-progressbar-name, at severity error. It covers every element with role="progressbar", and every native <progress> that carries no explicit role.

A name is accepted from a non-empty aria-label, an aria-labelledby pointing at an element with text, a non-empty title, or a <label for="..."> matching the element’s id.

  • Fail with N progressbar element(s) without accessible names. Every offender is listed, as progress#id or div[role="progressbar"].
  • Pass with All progressbar elements have accessible names.
  • Info with No progressbar elements found.
  • aria-progressbar-name-unconfirmed warns with N progressbar element(s) without accessible names may be hidden by a style (unconfirmed) for a progressbar a style may hide in a way squirrel cannot settle.

Hidden progressbars

A progressbar out of the accessibility tree has nothing to announce, so it is not reported: one with the hidden attribute (except hidden="until-found"), aria-hidden="true" on itself or an ancestor, display: none on itself or an ancestor (set inline or by a <style> rule squirrel can decide), or inside a closed <dialog> or an unopened popover. It still needs a name before it is shown. When every unnamed one is skipped this way, the pass reads All progressbar elements in the accessibility tree have accessible names, with hiddenWithoutName in its details.

squirrel reads the markup, inline styles and the page’s <style> blocks, the same way as form-labels; see form-labels for what it can and cannot decide. External stylesheets are not read. A progressbar that carries a no-js class, itself or on an ancestor other than <html>, is reported as unconfirmed on a page with an external stylesheet or an @import, because a theme usually hides that fallback with a rule such as .js .no-js { display: none } once JavaScript runs.

How to fix it

<label for="upload">Upload progress</label>
<progress id="upload" value="50" max="100">50%</progress>

An indeterminate progress bar, one with no value, still needs a name. It is announced as busy, and the name is the only thing that says what is busy.

For a custom role="progressbar", add aria-valuenow alongside the name so the widget reports its position. Leave aria-valuenow off when the progress is indeterminate, which is how that state is signalled, and leave aria-valuemin and aria-valuemax off unless the range differs from the default 0 to 100.

Rule IDa11y/aria-progressbar-name
CategoryAccessibility
ScopePer-page
Severityerror
Weight7/10

Enable / disable

Disable this rule

[rules]
disable = ["a11y/aria-progressbar-name"]

Disable all Accessibility rules

[rules]
disable = ["a11y/*"]

Enable only this rule

[rules]
enable = ["a11y/aria-progressbar-name"]

enable replaces the default ["*"], so this is the only rule selected. Leave disable out: a rule that matches any disable pattern is skipped even when enable names it. Only an enabled setting under a rule’s own [rule_options] table overrides both lists.

Accessibility findings ship in every audit next to the SEO, performance and agent experience rules. See Website security scan with AI for how an agent works through a report.

References

Check your site

Run squirrel audit https://example.com and open the Accessibility section of the report. Every unnamed progress bar is listed, with no cap on the count. Signed-out local audits need no account and cost nothing. Signed-in audits spend credits.

Type to search…

↑↓ navigate↵ openesc close