Scanverra

How to Fix Duplicate HTML IDs

An id attribute is supposed to name exactly one element on the page. When two elements share one, the browser doesn't error - it just quietly picks the first match every time something asks for that id, which is rarely the behavior anyone intended.

Where Duplicate IDs Come From

  • A hardcoded id inside a reusable component. A modal, tab panel, or form field component with id="email-input"baked in produces a collision the instant it's rendered more than once on a page.
  • Server-rendered fragments concatenated together. Two independently-built page sections (a header widget plus a CMS block, for example) each define their own id="cta" without knowing about the other.
  • Copy-pasted markup during a redesign. A section gets duplicated for an A/B test or a new variant, and the ids come along for the ride unchanged.

What Actually Breaks

  • Form labels. <label for="email"> only ever associates with the first id="email" in the DOM - clicking a second label with the same target focuses the wrong field, or nothing at all.
  • In-page anchors. A nav link to #pricing jumps to whichever id="pricing" comes first, even if the one you meant to link to is further down the page.
  • JavaScript selectors. document.getElementById() and querySelector("#id") both return only the first match - click handlers, state bindings, or accessibility attributes (aria-labelledby) can silently attach to the wrong element.

How to Fix It

1. Never hardcode an id inside a component that renders more than once

Generate a unique id per instance instead of hardcoding onetypescript
1import { useId } from "react";
2
3function FormField({ label }: { label: string }) {
4  const id = useId();
5  return (
6    <div>
7      <label htmlFor={id}>{label}</label>
8      <input id={id} />
9    </div>
10  );
11}

2. Prefer classes for styling, ids only for genuinely unique targets

If an id is only there to be a CSS hook, it almost certainly should be a class instead - classes are meant to repeat, ids aren't.

3. Audit merged/concatenated page sections

When a page is assembled from independently maintained fragments (a CMS block plus a hardcoded header, for example), grep each fragment's ids against the others before shipping - this is the collision source that's hardest to catch by just reading one file in isolation.

How Scanverra Detects This

Scanverra's browser test crawls the live rendered DOM - not just the raw HTML source - and collects every id attribute on the page, flagging any value that appears more than once so you get the exact duplicated id rather than having to hunt for it manually.

FAQ

Frequently asked questions

Is a duplicate id actually invalid HTML, or just bad practice?

It's invalid per the HTML specification - id values must be unique within a document. Browsers won't throw a visible error, which is exactly why it slips through unnoticed for years on real sites.

What breaks first when two elements share an id?

document.getElementById() and CSS #id selectors only ever return or style the first matching element - so a form label's for attribute, a JavaScript click handler, or an anchor link (#section) can silently target the wrong element, or the wrong one entirely, if the intended one isn't first in the DOM.

Why would this happen on a site built with a component framework?

Almost always a repeated component - a card, an accordion item, a form field - that hardcodes an id instead of generating one per instance. Render the same component twice on a page and you get two identical ids.

Does this actually affect SEO or just accessibility?

Primarily accessibility and functionality - a duplicate id breaks the label-to-input association screen readers rely on, and can break in-page anchor navigation. It's not a direct ranking factor, but a page with broken interactive elements often correlates with worse engagement signals.

Free - no sign-up required

Find every duplicate ID on your site

Run a browser test and get a real-browser crawl of every page, not just a static HTML scan.

Run free audit