WCAG Success Criteria · Level A

WCAG 4.1.1: Parsing (Deprecated in WCAG 2.2)

WCAG 4.1.1 Parsing requires that web content be free of major HTML/XML errors—such as duplicate IDs—that could cause assistive technologies to misinterpret or fail to process the page. Although deprecated in WCAG 2.2, the underlying axe-core rules remain active and violations still indicate real accessibility risk.

  • Level A
  • Wcag
  • Wcag 2 2 a
  • Robust
  • Accessibility

What This Rule Means

WCAG 4.1.1 Parsing was originally designed to ensure that user agents, including browsers and assistive technologies, could accurately parse and interpret web content. The criterion required that pages authored in markup languages such as HTML or XML satisfy four structural conditions: elements must have complete start and end tags; elements must be nested according to their specifications; elements must not contain duplicate attributes; and any IDs used in the content must be unique.

In WCAG 2.2, the W3C formally deprecated this criterion. The rationale was that modern browsers have become highly resilient to malformed HTML, auto-correcting most structural errors before they ever reach the accessibility tree. As a result, many of the original concerns—such as unclosed tags or improperly nested elements—no longer cause practical harm to assistive technologies in contemporary environments.

However, deprecation does not mean the criterion's concerns have disappeared entirely. The W3C explicitly notes that duplicate ID attributes remain a meaningful accessibility problem. When two or more elements share the same id value, browsers must make an arbitrary decision about which element to associate with ARIA references, label associations, or fragment links. This ambiguity can cause screen readers to announce incorrect content, skip interactive controls, or fail to expose form labels altogether. The criterion's pass condition is therefore best understood today as: no duplicate ID values appear in the DOM. A page fails this criterion when IDs are duplicated in ways that break programmatic associations relied upon by assistive technologies.

Official exceptions in the WCAG specification are minimal. The criterion applies to content authored in markup languages; it does not apply to content generated by scripting environments where the author has no direct control over the output format. In practice, however, developers are responsible for the final rendered DOM regardless of the technology stack used to produce it.

Why It Matters

Duplicate IDs may appear to be a minor housekeeping issue, but their consequences for users of assistive technology can be severe. Screen readers such as JAWS, NVDA, and VoiceOver rely on the browser's accessibility tree, which in turn depends on correctly resolved ID references to build the relationships between interface elements. When an ID is duplicated, the browser typically resolves references only to the first matching element in document order, silently ignoring subsequent elements with the same ID.

For blind and low-vision users, this can mean that a form field is announced without its label, or that an error message associated with an input via aria-describedby is never read aloud. Consider a checkout form on an e-commerce site where the shipping address fields and billing address fields both use IDs like city, zip, and state. A screen reader user filling out the billing section may hear the label from the shipping section instead, leading to confusion, errors, and potential abandonment of the transaction.

For users with cognitive disabilities, broken label associations mean that the visible text they read on screen does not match what their screen reader or voice control software announces, creating a disorienting disconnect that increases cognitive load.

For motor-impaired users relying on voice input software such as Dragon NaturallySpeaking, duplicate IDs can cause voice commands targeting a specific control to activate the wrong element, because the software may rely on ID-based targeting internally.

Beyond disability impact, duplicate IDs also affect SEO: search engine crawlers that rely on fragment identifiers for indexing specific page sections may index incorrect content when IDs are not unique. Usability is also degraded for all users when in-page anchor links navigate to the wrong location on the page.

Approximately 2.2 billion people worldwide have some form of vision impairment according to the World Health Organization. A significant proportion of those users rely on screen readers that are directly impacted by broken ID associations. Ensuring unique IDs is one of the lowest-effort, highest-impact fixes a development team can implement.

Three axe-core rules map directly to the concerns raised by WCAG 4.1.1. Each targets a specific manifestation of the duplicate ID problem:

  • duplicate-id: This rule checks the entire DOM for any id attribute value that appears on more than one element. It flags all elements beyond the first that share an ID, regardless of whether those elements are interactive or referenced by ARIA. This is the broadest of the three rules and catches structural violations even when no explicit ARIA relationship is involved. A common trigger is component-based frameworks that render the same reusable component multiple times on a page without generating unique IDs for each instance.
  • duplicate-id-active: This rule narrows its focus to duplicate IDs on elements that are interactive or focusable—buttons, links, inputs, and any element with a non-negative tabindex. The accessibility impact is elevated here because assistive technologies and keyboard navigation both depend on the ability to unambiguously identify an active control. When a submit button and an unrelated icon share the same ID, tab order announcements and programmatic focus management may both break.
  • duplicate-id-aria: This is the most critical of the three rules. It flags duplicate IDs specifically when those IDs are referenced by ARIA attributes—aria-labelledby, aria-describedby, aria-controls, aria-owns, and similar relationship attributes. Because these attributes are the primary mechanism through which assistive technologies understand the relationships between elements, duplicates here directly break accessible name computation and role relationships. A failing example would be two <div> elements with id='dialog-title' when a modal uses aria-labelledby='dialog-title'—the screen reader will announce whichever element appears first in the DOM, which may not be the intended dialog heading.

Automated tools are well-suited to catching duplicate IDs because the check is purely syntactic: the tool reads the DOM and compares ID values. No manual testing is strictly required for this criterion. However, if IDs are generated dynamically after user interaction—for example, an infinite scroll that injects new content with repeated IDs—automated scans run at page load may miss violations that only appear later. In such cases, testers should trigger the dynamic behavior before running scans, or monitor the DOM using browser developer tools after interactions.

How to Test

  1. Automated scan with axe DevTools: Open the page in Chrome or Firefox. Open DevTools (F12), navigate to the axe DevTools panel (or install the browser extension), and run a full-page scan. Filter results for the rules duplicate-id, duplicate-id-active, and duplicate-id-aria. Each violation will list the affected elements and their duplicate ID values. Export the report if needed for audit documentation. For Lighthouse, run a Lighthouse accessibility audit from the DevTools Lighthouse tab and look for the "Document has multiple elements with the same id" audit.
  2. Browser DevTools console check: Open the browser console and run the following JavaScript snippet to find all duplicate IDs on the current page: const ids = [...document.querySelectorAll('[id]')].map(el => el.id); const dupes = ids.filter((id, i) => ids.indexOf(id) !== i); console.log([...new Set(dupes)]); This will print an array of all ID values that appear more than once. An empty array means no duplicates are present.
  3. Screen reader testing with NVDA and Firefox: Load the page with NVDA running. Navigate to a form that contains fields with labels associated via for/id or aria-labelledby. Tab through each field and listen carefully to whether NVDA announces the correct label. If a field is announced with no label, or with the wrong label from a different section, a duplicate ID may be the cause. Repeat this process for any ARIA landmark regions, modal dialogs, or widgets that use aria-controls or aria-describedby.
  4. VoiceOver and Safari on macOS: Enable VoiceOver (Command+F5). Use the VoiceOver rotor (Control+Option+U) to open the Form Controls or Links list and verify that each control has a unique, correctly announced label. Navigate into any modal dialogs and confirm the dialog title is announced correctly when the dialog opens.
  5. JAWS and Chrome: With JAWS running, open the page and use the JAWS list of form fields (Insert+F5) to review all form elements and their associated labels. Verify no two fields share the same label text when they should be distinct.
  6. Dynamic content testing: If the page uses infinite scroll, single-page navigation, or modal dialogs injected via JavaScript, interact with these features to load new content into the DOM, then re-run the automated scan or console snippet to check for duplicates introduced by the dynamic content.

How to Fix

Duplicate form field IDs across repeated sections — Incorrect

<!-- Shipping Address -->
<label for='city'>City</label>
<input type='text' id='city' name='shipping-city'>

<!-- Billing Address -->
<label for='city'>City</label>
<input type='text' id='city' name='billing-city'>
<!-- FAIL: Both inputs share id='city'. The second label's 'for' attribute
     resolves to the first input, so screen readers announce the wrong field. -->

Duplicate form field IDs across repeated sections — Correct

<!-- Shipping Address -->
<label for='shipping-city'>City</label>
<input type='text' id='shipping-city' name='shipping-city'>

<!-- Billing Address -->
<label for='billing-city'>City</label>
<input type='text' id='billing-city' name='billing-city'>
<!-- PASS: Each input has a unique ID scoped to its section.
     Screen readers correctly announce each field's label. -->

Reusable component rendered multiple times — Incorrect

<!-- Product Card 1 -->
<div class='product-card'>
  <img id='product-img' src='shoe.jpg' alt='Running Shoe'>
  <button id='add-to-cart' aria-describedby='product-desc'>Add to Cart</button>
  <p id='product-desc'>Free shipping on orders over 500 TL.</p>
</div>

<!-- Product Card 2 (same template, duplicate IDs) -->
<div class='product-card'>
  <img id='product-img' src='boot.jpg' alt='Hiking Boot'>
  <button id='add-to-cart' aria-describedby='product-desc'>Add to Cart</button>
  <p id='product-desc'>Free shipping on orders over 500 TL.</p>
</div>
<!-- FAIL: IDs duplicated across cards. aria-describedby on the second button
     resolves to the <p> in the first card, not the second. -->

Reusable component rendered multiple times — Correct

<!-- Product Card 1 -->
<div class='product-card'>
  <img id='product-img-1' src='shoe.jpg' alt='Running Shoe'>
  <button id='add-to-cart-1' aria-describedby='product-desc-1'>Add to Cart</button>
  <p id='product-desc-1'>Free shipping on orders over 500 TL.</p>
</div>

<!-- Product Card 2 -->
<div class='product-card'>
  <img id='product-img-2' src='boot.jpg' alt='Hiking Boot'>
  <button id='add-to-cart-2' aria-describedby='product-desc-2'>Add to Cart</button>
  <p id='product-desc-2'>Free shipping on orders over 500 TL.</p>
</div>
<!-- PASS: Each card's IDs are unique. ARIA references resolve correctly
     within their own card. Use a counter, UUID, or slug-based strategy
     to generate IDs in your component framework. -->

Modal dialog with duplicate ARIA label reference — Incorrect

<!-- A generic heading used as a reusable ID -->
<h1 id='dialog-title'>Welcome</h1>

<div role='dialog' aria-modal='true' aria-labelledby='dialog-title'>
  <h2 id='dialog-title'>Confirm Your Order</h2>
  <p>Are you sure you want to place this order?</p>
  <button>Confirm</button>
  <button>Cancel</button>
</div>
<!-- FAIL: Two elements share id='dialog-title'. The dialog's
     aria-labelledby resolves to the page <h1>, not the dialog heading.
     Screen readers will announce 'Welcome' as the dialog name. -->

Modal dialog with duplicate ARIA label reference — Correct

<h1>Welcome</h1>

<div role='dialog' aria-modal='true' aria-labelledby='confirm-dialog-title'>
  <h2 id='confirm-dialog-title'>Confirm Your Order</h2>
  <p>Are you sure you want to place this order?</p>
  <button>Confirm</button>
  <button>Cancel</button>
</div>
<!-- PASS: The dialog heading has a unique, descriptive ID.
     aria-labelledby correctly identifies the dialog to screen readers
     as 'Confirm Your Order'. -->

Common Mistakes

  • Copy-pasting component markup without updating IDs: Developers often duplicate a working section of HTML for a second instance (a second address block, a second tab panel, a second accordion item) and forget to update all ID values to be unique. Establish a naming convention such as component-name-index (e.g., accordion-panel-1, accordion-panel-2) and enforce it in code review.
  • Using static IDs in framework components without a unique key strategy: React, Vue, Angular, and similar frameworks can render the same component dozens of times on one page. Using a hardcoded id='search-input' inside a reusable component will create as many duplicates as there are instances. Always derive IDs from props, a counter, or a utility like useId() in React 18+.
  • Relying on CSS class targeting instead of fixing the HTML: Some developers work around duplicate ID issues by switching JavaScript selectors from getElementById to querySelector with a class, while leaving the duplicate IDs in place. This may fix visual behavior but does nothing to resolve the broken accessibility tree associations.
  • Server-side templating loops that generate the same ID on every iteration: A Jinja2, Blade, or Twig template that renders id='item-title' inside a {% for item in items %} loop will produce one duplicate for every item in the list. Always append the loop index or item identifier to the ID: id='item-title-{{ loop.index }}'.
  • Ignoring duplicate IDs in hidden or off-screen elements: Elements with display: none or visibility: hidden are still present in the DOM and their IDs are still registered. A hidden modal template that shares an ID with a visible element will cause the same parsing failures. Use hidden attribute or ensure hidden templates use unique IDs.
  • Assuming that scoping to a Shadow DOM resolves the issue: IDs inside native Shadow DOM are scoped and do not conflict with IDs in the light DOM or other shadow roots. However, many component libraries use a polyfill or non-standard approach that does not provide true scoping. Verify actual DOM output rather than assuming framework behavior.
  • Generating IDs based on user-supplied content without sanitization or deduplication: Creating IDs from product names, article titles, or other dynamic text can produce collisions when two items share the same name (e.g., two products both called "Classic" both generating id='classic'). Always append a unique database key or index to content-derived IDs.
  • Not testing after client-side navigation in single-page applications: SPAs that inject new route content into the DOM without a full page reload can accumulate IDs from previously visited routes if old content is not properly unmounted. Run axe scans after navigating between routes, not just on initial load.
  • Forgetting IDs used in SVG <defs> and <use> elements: SVG sprite patterns that define symbols with IDs inside <defs> and then reference them with <use href='#icon-arrow'> can create duplicate IDs if the same symbol definition is included multiple times on a page. Centralize SVG sprite definitions and include them only once.
  • Overlooking IDs generated by third-party widgets, chat plugins, or analytics scripts: Third-party scripts sometimes inject elements with hardcoded IDs. If your own code uses the same ID, a conflict arises that you may not notice during development. Audit the full rendered DOM including third-party content, and report conflicts to vendors or namespace your own IDs to avoid collisions.

Relation to Turkey's Accessibility Regulations

Turkey's Presidential Circular 2025/10, published in the Official Gazette numbered 32933 on June 21, 2025, establishes mandatory web accessibility requirements for a broad set of public and private entities operating in Turkey. The circular adopts WCAG 2.2 as its technical reference standard, making Level A conformance the minimum legal baseline for all covered entities.

WCAG 4.1.1 Parsing is a Level A criterion. Even though W3C deprecated it in WCAG 2.2, the axe-core rules that enforce its primary concern—unique IDs—remain active and continue to be flagged in accessibility audits conducted against WCAG 2.2. Turkish regulatory audits and conformance reviews that use automated scanning tools will therefore flag duplicate-id violations as potential Level A failures, regardless of the criterion's deprecated status at the spec level. Organizations seeking to demonstrate compliance should treat duplicate ID violations as blocking issues.

The entities covered by Presidential Circular 2025/10 include a wide range of public institutions and private sector organizations: all central and local government bodies and their affiliated agencies; banks and financial institutions regulated under Turkish banking law; hospitals and private healthcare providers; telecommunications operators serving 200,000 or more subscribers; e-commerce platforms and online marketplaces; travel agencies and tour operators; private transport companies operating under public concessions; and private schools and educational institutions authorized by the Ministry of National Education (MoNE).

The circular establishes a phased compliance timeline. Public institutions must achieve full Level A conformance within one year of the circular's publication date. Private sector entities in the covered categories have two years to reach the same standard. Failure to comply exposes covered entities to regulatory scrutiny, potential administrative sanctions, and reputational risk in an increasingly accessibility-aware market.

For Turkish organizations, addressing duplicate ID violations is particularly relevant in contexts where digital forms, online payment flows, government service portals, and healthcare booking systems are involved. These are precisely the interface types most likely to use repeated form sections, reusable components, and third-party widget integrations that introduce duplicate IDs. Establishing automated accessibility testing—such as integrating axe-core into CI/CD pipelines—as part of the development process is both a technical best practice and a pragmatic strategy for maintaining ongoing regulatory compliance under the circular's requirements.