IDs Used in ARIA and Labels Must Be Unique: How to Fix It

No Comments
Ids used in aria and labels must be unique: how to fix it

What this check flags

This check fails when the same id value appears more than once and that id is being pointed at by an ARIA relationship (aria-labelledby, aria-describedby, aria-controls) or a <label for>. It matters because when a reference resolves an id, the browser stops at the first match — so a duplicate quietly hands the wrong label, or no usable label, to everyone using a screen reader.

The axe-core rule is duplicate-id-aria (and its cousin duplicate-id-active for focusable elements). Plain HTML already says id must be unique in a document; this check is the accessibility-critical subset where a duplicate doesn't just look sloppy, it breaks a real relationship a person depends on.

A real failing example, and the fix

Two search boxes on the same page — one in the header, one in a sidebar — built from the same partial. Both labels ended up with id="search-label".

<!-- FAILING: id="search-label" used twice -->
<!-- header -->
<label id="search-label">Search the site</label>
<input type="search" aria-labelledby="search-label">

<!-- sidebar, further down the page -->
<label id="search-label">Search help articles</label>
<input type="search" aria-labelledby="search-label">

Both inputs resolve aria-labelledby="search-label" to the first element with that id — the header's "Search the site." So the sidebar's help search is announced as "Search the site," which is simply wrong. The user searching the help center has no idea they're in the wrong box.

<!-- FIXED: unique ids, each reference resolves correctly -->
<label id="site-search-label">Search the site</label>
<input type="search" aria-labelledby="site-search-label">

<label id="help-search-label">Search help articles</label>
<input type="search" aria-labelledby="help-search-label">

Same visible page. Now each input announces its own purpose.

How a duplicate id actually breaks each relationship

ReferenceWhat it should doWhat a duplicate id does instead
aria-labelledby="x"Name the element from the text of #xGrabs the first #x — wrong or misleading name
aria-describedby="x"Attach the description in #xAttaches the first #x's text, or the wrong hint
<label for="x">Bind the label to input #xBinds to the first #x; the second input is unlabeled and its click target is lost
aria-controls="x"Say this control operates #xPoints at the wrong region — focus/state moves to the wrong place

The through-line: ID resolution is "first match wins," and it fails silently. Nothing in the visible page or a casual source review reveals it — you only see it in the accessibility tree or when a screen reader reads the wrong thing aloud.

Where duplicate IDs come from

Almost never from someone typing the same id twice on purpose. The usual culprits: a reusable component or template partial rendered more than once on a page (each copy carries the same hardcoded id); a CMS or page builder that stamps a fixed id into every instance of a block; loops that build markup from a template string without appending an index; and content pasted from another page that brought its id along.

How to detect it

  1. axe DevTools — run it and look for duplicate-id-aria / "IDs used in ARIA and labels must be unique." It lists every clashing id and the elements involved.
  2. Lighthouse Accessibility audit — surfaces the same failure as "[id] attributes on active, focusable elements are not unique" or the ARIA-id variant.
  3. Browser console: document.querySelectorAll('[id]') and check for repeats — a two-line script counting id occurrences finds them fast on a rendered page.
  4. An HTML validator (validator.w3.org) — it reports "Duplicate ID" independent of ARIA, useful for catching the whole class of problem across a template.

How to fix it

  1. List every duplicated id from the report, and note which references (aria-labelledby, for, etc.) point at each one.
  2. Make each id unique — prefix by context (site-search-label vs help-search-label) or append the instance index in loops (option-1, option-2).
  3. Update every reference that pointed at the old id in lockstep. A renamed id with a stale aria-labelledby pointing at nothing is a new failure (a broken reference), not a fix.
  4. Fix it in the component/template so repeated instances generate distinct ids automatically — framework id helpers (React's useId, Vue/Angular equivalents) exist for exactly this.
  5. Re-scan the rendered page to confirm both the duplicate and any dangling references are clear.

FAQ

Is a duplicate id an SEO problem or only an accessibility one?

It's an accessibility failure first — a real person gets the wrong label. It touches SEO the same way other a11y defects do: a lower Lighthouse accessibility score and the general "is this a well-built page" signal. Invalid, non-unique id markup is also just malformed HTML, which is worth cleaning up on its own merits.

Do IDs that aren't referenced by ARIA still need to be unique?

Yes — the HTML spec requires all id values to be unique per document, full stop. This particular check zeroes in on the ones wired into ARIA and labels because those cause the most visible harm, but a duplicate id anywhere can break CSS, anchor links, and JavaScript getElementById too.

Can I point two references at the same id on purpose?

Absolutely, and that's fine — many inputs legitimately share one aria-describedby hint. The rule isn't "an id may only be referenced once." It's "an id may only be defined once." One id, many pointers: good. Two elements claiming the same id: broken.

My framework generates the IDs. Why am I still failing?

Usually because a component with a hardcoded id got rendered more than once, or a list keyed off content that repeats. Switch to the framework's unique-id utility so each instance mints its own id, and stop hardcoding ids inside anything that can render twice.

Related checks

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