Skip to main content

About This Accessibility Rule

Why This Is an Accessibility Problem

In HTML, the id attribute is designed to be a unique identifier for a single element in the document. When two or more elements share the same id, the browser has no reliable way to determine which element is being referenced. This becomes a critical accessibility barrier when that id is used to create relationships between elements — such as linking a <label> to a form input, or connecting a description to a widget via aria-describedby.

Assistive technologies like screen readers rely on these id-based relationships to communicate information to users. When duplicates exist, the screen reader will typically resolve the reference to the first element in the DOM with that id, which may not be the intended target. This means:

  • A blind or deafblind user may hear the wrong label for a form field, or no label at all.
  • An ARIA relationship like aria-labelledby or aria-describedby may point to the wrong content, giving users incorrect or missing context.
  • Interactive components that depend on aria-owns, aria-controls, or aria-activedescendant may break entirely.

This rule relates to WCAG Success Criterion 4.1.2: Name, Role, Value (Level A), which requires that all user interface components have accessible names and roles that can be programmatically determined. Duplicate id values used in ARIA or label associations directly undermine this requirement by creating ambiguous or broken programmatic relationships.

How to Fix It

  1. Identify all duplicate id values that are referenced by ARIA attributes (aria-labelledby, aria-describedby, aria-controls, aria-owns, aria-activedescendant, etc.) or by a <label> element’s for attribute.
  2. Rename the duplicate id values so that each one is unique within the document.
  3. Update any references to those id values in ARIA attributes or for attributes to match the new unique values.
  4. Verify that each relationship still works correctly by testing with a screen reader or the axe accessibility checker.

Examples

Incorrect: Duplicate id on elements referenced by for

In this example, two inputs share the same id of "email". The second <label> intends to reference the second input, but both for attributes resolve to the first input.

<label for="email">Personal Email</label>
<input type="email" id="email">

<label for="email">Work Email</label>
<input type="email" id="email">

A screen reader user tabbing to the second input would hear no label or the wrong label, making it impossible to know what information to enter.

Correct: Unique id values for each input

<label for="personal-email">Personal Email</label>
<input type="email" id="personal-email">

<label for="work-email">Work Email</label>
<input type="email" id="work-email">

Incorrect: Duplicate id referenced by aria-labelledby

<span id="section-title">Shipping Address</span>
<div role="group" aria-labelledby="section-title">
<!-- shipping fields -->

</div>

<span id="section-title">Billing Address</span>
<div role="group" aria-labelledby="section-title">
<!-- billing fields -->

</div>

Both groups would be announced as “Shipping Address” because the browser resolves both aria-labelledby references to the first <span> with id="section-title".

Correct: Unique id values for each referenced element

<span id="shipping-title">Shipping Address</span>
<div role="group" aria-labelledby="shipping-title">
<!-- shipping fields -->

</div>

<span id="billing-title">Billing Address</span>
<div role="group" aria-labelledby="billing-title">
<!-- billing fields -->

</div>

Incorrect: Duplicate id used in aria-describedby

<p id="hint">Must be at least 8 characters.</p>
<label for="password">Password</label>
<input type="password" id="password" aria-describedby="hint">

<p id="hint">Re-enter your password to confirm.</p>
<label for="confirm-password">Confirm Password</label>
<input type="password" id="confirm-password" aria-describedby="hint">

Correct: Unique id values for each description

<p id="password-hint">Must be at least 8 characters.</p>
<label for="password">Password</label>
<input type="password" id="password" aria-describedby="password-hint">

<p id="confirm-hint">Re-enter your password to confirm.</p>
<label for="confirm-password">Confirm Password</label>
<input type="password" id="confirm-password" aria-describedby="confirm-hint">

Help us improve our guides

Was this guide helpful?

Detect accessibility issues automatically

Rocket Validator scans thousands of pages with Axe Core and the W3C Validator, finding accessibility issues across your entire site.

Ready to validate your sites?
Start your trial today.