Avoid duplicate IDs used in ARIA attributes or relationships

WCAG 4.1.1
Parsing

Content available in English only.

Accessibility isn't just about avoiding violations — it's about ensuring that everyone can use your product with confidence. This guide explains each rule's intent, highlights common issues, and shows how to fix them according to WCAG and the European Accessibility Act (EAA).

These guidelines do not replace the official WCAG standards. They’re concise, developer-focused notes to help you identify and fix issues effectively.

Each ID used in ARIA attributes must be unique — never reuse for multiple elements.

Overview

Why this matters

ARIA relationships such as aria-labelledby, aria-describedby, aria-controls, and aria-owns rely on unique IDs to bind elements together. If multiple elements share a referenced ID, screen readers may announce the wrong label, skip the description, or provide inconsistent navigation, making forms and controls confusing or unusable.

How to fix this issue

Ensure every ID referenced in ARIA attributes is unique on the page. If a component is duplicated, generate new IDs per instance. When describing multiple elements, reference multiple unique IDs in the ARIA attribute rather than repeating one.

Automated detection · Manual review recommended

Developer Guidance

This issue most often appears in cloned UI widgets, repeated field groups, modal/tooltip systems, and component libraries where IDs are hardcoded. In React, use `useId()` or a prefix+index pattern; in Vue/Angular, scope IDs using component instance identifiers.

Code Examples

Incorrect Implementation

<input aria-labelledby="label1" />
<span id="label1">Name</span>
<span id="label1">Full name</span>

Correct Implementation

<input aria-labelledby="label1" />
<span id="label1">Name</span>
<span id="label2">Full name</span>

Real-World Implementation

Before

<div v-for="item in users">
  <label id="user-label">User Name</label>
  <input aria-labelledby="user-label" />
</div>
<!-- Every row references the same ID → all fields are announced the same -->

After

<div v-for="(item, index) in users">
  <label :id="`user-label-${index}`">User Name</label>
  <input :aria-labelledby="`user-label-${index}`" />
</div>
<!-- Each label/input relationship is now distinct and announced correctly -->

Manual Testing

  1. 1. Open the page and inspect repeated or dynamic UI elements (forms, lists, modals, tooltips).
  2. 2. In DevTools, search for the ID used in aria-labelledby or aria-describedby.
  3. • Expected: each ID appears only once in the DOM.
  4. 3. Turn on a screen reader (VoiceOver, NVDA, or TalkBack).
  5. 4. Navigate to each repeated field using arrow keys.
  6. • Expected announcement: each input is announced with the correct label.
  7. • Failure: every input is announced with the same label, or labels seem incorrect or missing.
  8. 5. If UI supports adding new rows dynamically (e.g., Add User, Add Item), trigger that action and repeat the test to ensure IDs remain unique at runtime.

Related Robust Rules

eu icon getwcag

Trusted by organizations across Europe working toward WCAG and EAA conformance