See plans and pricing

IDs used in ARIA and labels must be unique

Estimated effort: about 10 minutes.

When two elements on the same page share the same id, and that id is referenced by a <label for="...">, aria-labelledby, or another ARIA attribute, assistive technology can only reliably connect to the first matching element. The second one effectively loses its label or its ARIA relationship, which commonly happens on product-listing pages where the same add-to-cart form (with its own quantity input id) is repeated for every product in a loop.

How to fix it

  1. Find every id value that is referenced by a <label for="...">, aria-labelledby, aria-describedby, aria-controls, or similar ARIA attribute, and check whether that same id string appears on more than one element in the page's HTML.
  2. This is a common risk on product-listing/category pages, where a repeating "loop" template (one block of markup reused for every product card) can end up giving every card's quantity input, label, or accordion panel the exact same static id if the template does not generate a unique id per product.
  3. Fix it by making the id unique per instance — append the product's ID or SKU to the id string (e.g. id="qty-123" for product 123 rather than a static id="qty"), or generate the id dynamically at render time.
  4. After the fix, re-scan the page's rendered HTML (view-source, not the template code) to confirm no id value used in a label or ARIA attribute is duplicated.
  5. Also check quick-view modals and mini-cart widgets that can appear on the same page as the main content — if both reuse the same static ids as the main page's fields, this creates the same conflict even though they look like separate, unrelated components.

WooCommerce note

WooCommerce's default quantity input template (global/quantity-input.php) generates a unique field id per instance using PHP's uniqid('quantity_'), so out-of-the-box duplicate IDs on quantity inputs are unlikely. If this issue appears on a cart or product-listing page, check for a custom loop template, a caching/quick-view plugin, or a theme override that replaced this default id generator with a static, hardcoded id.

Before and after

Before

<!-- Product card #1 -->
<label for="qty">Quantity</label>
<input type="number" id="qty" value="1">

<!-- Product card #2, reused from the same loop template -->
<label for="qty">Quantity</label>
<input type="number" id="qty" value="1">

After

<!-- Product card #1 -->
<label for="qty-123">Quantity</label>
<input type="number" id="qty-123" value="1">

<!-- Product card #2 -->
<label for="qty-456">Quantity</label>
<input type="number" id="qty-456" value="1">

View the full rule reference from Deque University

See plans and pricing