How to fix duplicate id attributes?
duplicate-id-aria page
The issue
An id is meant to identify one element. When two share it, anything that points to that id finds only one of them, usually the first. If a button’s name or a field’s error message comes from aria-labelledby or aria-describedby, a screen reader can read out the wrong element’s text. A field may be announced with another field’s label, or with an error that belongs elsewhere.
The cause is usually repetition: a component rendered several times with a hard-coded id, or a template that includes the same block twice. Where the duplicated id is referenced by ARIA, WCAG 4.1.2 applies, because the element’s name and description are what’s at stake. Plain duplicates fall under WCAG 4.1.1, which WCAG 2.2 marks as obsolete.
Scope
Two rules check ids across the whole page, including hidden elements:
duplicate-id-arialooks only at ids referenced by anaria-labelledbyoraria-describedbysomewhere on the page. Every element sharing one of those ids is reported.duplicate-idlooks at everyid. Every element sharing a value with another is reported.
How to check you have it
- In probeo: the page reports
duplicate-id-aria, “IDs used in ARIA and labels must be unique”, with critical impact, andduplicate-id, “id attribute value must be unique”, with minor impact. Each names the repeated value. - By hand: in the browser console,
document.querySelectorAll('#the-id').lengthreturns more than 1 for a duplicate. - With a tool: axe DevTools reports both rules by the same names, and the W3C Nu HTML Checker reports duplicate IDs.
The fix
Make every id on the page unique, starting with the ones ARIA attributes point to.
For components rendered more than once, generate the id from something unique to each instance, and update every aria-labelledby, aria-describedby and for that refers to it.
<!-- Each field gets its own id, and its hint points to it -->
<input id="email-billing" aria-describedby="email-billing-hint">
<p id="email-billing-hint">We send receipts here.</p>
<input id="email-shipping" aria-describedby="email-shipping-hint">
<p id="email-shipping-hint">We send tracking updates here.</p>Done when: no two elements share an id, and the check above comes back clean.
Do not
- Do not hard-code ids inside reusable components.
- Do not rename an
idwithout renaming the references to it. - Do not treat the minor
duplicate-idreports as harmless when the same value also shows up underduplicate-id-aria.
FAQ
Why is one rule critical and the other minor?
A duplicate id that ARIA points to can give a control the wrong name or description, which changes what a screen reader user hears. A duplicate that nothing points to is invalid markup but usually has no audible effect.
Do label for attributes count?
duplicate-id-aria follows aria-labelledby and aria-describedby only. A <label for> pointing at a duplicated id is still a problem, since the label attaches to the first match, and duplicate-id reports it.
Are hidden elements included?
Yes. An id on a hidden element still collides with a visible one, so both rules check every element on the page.
Which product detects this
Probeo checks this on every page of your site as part of Site Clarity. This page explains one instance; the product tells you every page that has it.