Prevent duplicate IDs in dynamically rendered components

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.

Generate a unique ID for every dynamic component — never reuse the same ID.

Overview

Why this matters

IDs are used to form accessibility relationships, such as associating labels with form inputs or linking elements using aria-controls and aria-describedby. If multiple elements share the same ID, assistive technologies and browser behavior become unpredictable. Screen readers may announce the wrong label or ignore the relationship entirely.

How to fix this issue

Ensure every ID is unique per component instance. When rendering lists, modals, forms, or repeatable UI elements, generate unique IDs using indexed suffixes, UUIDs, incrementing counters, or framework-specific ID helpers. Never hardcode IDs inside reusable components.

Automated detection · Manual review recommended

Developer Guidance

This issue is common when UI elements are rendered in loops or when a modal or tooltip component gets mounted multiple times. In libraries like React, accept `id` as a prop or use a stable ID generator (e.g., React's `useId()`). In Vue/Angular, scope IDs or use directive-based labeling instead of static values.

Code Examples

Incorrect Implementation

<Modal id="dialog" />
<Modal id="dialog" />

Correct Implementation

<Modal id="dialog-1" />
<Modal id="dialog-2" />

Real-World Implementation

Before

<ul>
  {items.map(() => (
    <input id="quantity" type="number" />
  ))}
</ul>
<!-- All inputs have id="quantity" → labels and errors announce incorrectly -->

After

<ul>
  {items.map((item, index) => (
    <input id={`quantity-${index}`} type="number" />
  ))}
</ul>
<!-- Each input receives a unique id tied to its position -->

Manual Testing

  1. 1. Open the page where dynamic components (lists, modals, form rows) appear.
  2. 2. Open browser DevTools → Elements tab.
  3. 3. Search for any ID value using CTRL+F and repeat searches (e.g., search: id="dialog"). Each ID should appear only once.
  4. 4. Turn on a screen reader (NVDA, VoiceOver, or TalkBack).
  5. 5. Navigate through repeated elements (e.g., multiple inputs).
  6. • Expected: each input is announced with the correct corresponding label.
  7. • Failure: labels are skipped, duplicated, or read out of context.
  8. 6. If the UI allows adding dynamic elements (e.g., Add Row / Add Item), repeat the test **after adding 2–5 items** to confirm IDs remain unique at runtime.

Related Robust Rules

eu icon getwcag

Trusted by organizations across Europe working toward WCAG and EAA conformance