squirrelscan
GitHub

ARIA references pointing at duplicate or missing ids

aria-labelledby resolving to two elements, or to none, names the wrong thing silently. squirrel checks all eight ARIA id references.

What an ARIA id reference is

Eight ARIA attributes work by pointing at other elements by id: aria-labelledby, aria-describedby, aria-controls, aria-owns, aria-activedescendant, aria-flowto, aria-details and aria-errormessage. Most take a whitespace-separated list; aria-activedescendant, aria-details and aria-errormessage take a single id. squirrel splits all eight on whitespace either way.

A reference that resolves to nothing loses whatever it was contributing, be that a name, a description or a relationship, and reports no error. A reference that resolves to two elements takes the first, which may not be the one you meant. Either way the failure is invisible until someone uses a screen reader.

What squirrel checks

One check, duplicate-id-aria, at severity error. It collects every id named by those eight attributes, splitting each value on whitespace, then counts every id on the page and compares.

  • Fail with N problematic ID(s) in ARIA attributes. Items read "settings-title" (2 occurrences) for a duplicate, or "settings-title" (not found) for a dangling reference. Up to ten are shown with a count of the rest.
  • Pass with All ARIA ID references are valid and unique.
  • Info with No ARIA ID references found.

Both failure modes land in one check, so read the item text to tell them apart. The rule inspects only the ids ARIA references. Unreferenced duplicates elsewhere on the page are out of scope.

How to fix it

<h2 id="billing-heading">Billing</h2>
<section aria-labelledby="billing-heading">...</section>

For a dangling reference, check the target still exists. Ids that disappear during a refactor are the common cause, and so are ids added by a framework at runtime that never make it into the server-rendered markup.

For a duplicate, rename one of the two. A component rendered twice on the same page needs a generated id, not a hard-coded one.

Rule IDa11y/duplicate-id-aria
CategoryAccessibility
ScopePer-page
Severityerror
Weight8/10

Enable / disable

Disable this rule

[rules]
disable = ["a11y/duplicate-id-aria"]

Disable all Accessibility rules

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

Enable only this rule

[rules]
enable = ["a11y/duplicate-id-aria"]

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. Duplicates and dangling references appear together, distinguished by the item text. Signed-out local audits need no account and cost nothing. Signed-in audits spend credits.

Type to search…

↑↓ navigate↵ openesc close