HTML Tutorial 0/139 lessons ~6 min read Lesson 24

    HTML Id

    html id the id attribute provides document-unique hooks for fragments, form labels, and the id attribute must be unique

    Course progress0%
    Focus
    18 guided sections
    Practice signal
    Examples included
    Career prep
    Interview Q&A included

    Introduction

    The id attribute must be unique per document — fragment URLs (#section), label associations (for/id), ARIA references (aria-labelledby), and CSS/JS hooks depend on it. Duplicate ids break accessibility APIs and querySelector unpredictability. Google One Tap and Stripe Elements document required container ids; BBC skip links target #main.

    Business problem

    Duplicate ids from copy-paste components, CMS loops, and React key mistakes cause wrong label association, broken in-page links, and GET form submissions targeting wrong field.

    • A11y: label for=email points to first id=email — second field unlabeled.
    • Support: Hash link #pricing scrolls to wrong section on long marketing pages.
    • Legal: WCAG 4.1.1 Parsing — duplicate ids fail compliance scans.

    Why this feature exists

    Fragment identifiers in URLs required named anchors — id replaced name attribute. Uniqueness enables single-point references across linking, CSS #foo, and getElementById O(1) map.

    • History: name anchors on a deprecated — id on any element.
    • XML: Stricter id rules — HTML5 allows almost any string except spaces.
    • Shadow DOM: ids scoped inside shadow — document-wide unique in light DOM only.

    Browser internals

    Document.getElementById returns first match in tree order — duplicates leave second orphaned for API purposes. CSS #id specificity (1,0,0) beats classes. url fragment navigates to element with matching id — scroll-margin-top affects landing.

    • aria-labelledby: Space-separated ids reference multiple elements.
    • Invalid: id starting with digit — CSS escape needed, valid in HTML5.
    • Dynamic: SPA route change shouldn't duplicate static layout ids across virtual pages if DOM persists.
    text
    getElementById('x') → first #x in document
    #pricing { scroll-margin-top: 80px; }
    aria-describedby="err1 err2" → concat accessible description

    Rendering workflow

    Fragment navigation triggers scroll without full navigation — instant for INP. Sticky header obscuring id target — fix with scroll-margin on :target. LCP unaffected unless hash scroll delays hero paint perception.

    • Scroll anchoring: Dynamic content above target shifts scroll — anchor nodes help.
    • Focus: Focus management on route id section — tabindex=-1 on h1 pattern.
    • History: pushState with hash updates scroll and screen reader context.

    Feature deep dive

    Use id for: fragment destinations, label/input pairing, ARIA relationships, and unique widget roots. Avoid styling with id — use class. Generate ids for repeated components with UUID suffix in SPAs.

    • Skip link: href="#main" + main id="main".
    • Heading ids: Auto from slug for deep links in docs — Stripe API reference pattern.
    • Forms: id on input matches label for — required for click-to-focus.
    html
    <a href="#faq">FAQ</a>
    <section id="faq" aria-labelledby="faq-heading">
    <h2 id="faq-heading">FAQ</h2>
    </section>
    <label for="email">Email</label>
    <input id="email" name="email" type="email">

    Accessibility analysis

    IDREF relationships power accessible name/description computation — broken id breaks entire form. Duplicate ids cause AT to reference wrong node — silent catastrophic failure. WCAG 4.1.1 requires unique ids where used.

    • aria-controls: Points to id of controlled region — tab panels.
    • aria-labelledby: Multiple ids — order matters in name.
    • Focus: Move focus to id=main on skip — tabindex=-1 on main.

    SEO impact

    Fragment URLs (page#section) may index as separate URLs if content substantially different — usually consolidated. Google sitelinks jump to hash sections on brand queries. Descriptive id slugs minor UX win in shared links — not ranking factor.

    • Canonical: Hash not sent to server — same URL base, different client section.
    • Jump links: Table of contents with hash links helps long article UX — indirect engagement signal.
    • Crawl: Googlebot follows hash in some JS apps — prefer real URLs for routes.

    Security considerations

    Fragment XSS historically — location.hash to innerHTML. Sanitize hash usage. Predictable ids (user-123) enable DOM clobbering if combined with named properties. Don't put secrets in id values — visible in DOM and URLs.

    • Open redirect: Unrelated to id — but hash navigation to attacker content in SPA if router naive.
    • Clobbering: id=length on input clobbers HTMLCollection — rare, sanitize user widgets.
    • Enumeration: Sequential ids in HTML leak object counts — low risk.

    Performance impact

    getElementById fast — prefer over querySelector('#x') in hot paths marginally. Thousands of unique ids don't hurt; duplicate ids cause wrong node updates — logical bugs. Auto-generated long UUID ids bloat HTML slightly on 500-field admin pages.

    • CSS: #id rules prevent tree-shaking unused rules — avoid id selectors in DS.
    • Hydration: Stable ids between server/client required for ARIA wiring.
    • SPA: Reuse ids after route swap without cleanup — duplicate explosion.

    Real production example

    Google documentation auto-ids headings from text slug — stable permalinks in MDX pipeline. Airbnb listing share links use canonical URL without fragile hash. Form fields use ids from server with collision check in component library.

    • Lint: eslint-plugin-unique-id or axe duplicate-id rule in CI.
    • CMS: Block authors from setting raw id — auto-generate.
    • Microfrontend: Prefix ids with app name — mfe-checkout-email.
    html
    <!-- Stripe-style mount point -->
    <div id="payment-element"></div>
    <label for="mfe-billing-email">Email</label>
    <input id="mfe-billing-email" >

    Enterprise usage

    Enterprise a11y gates fail builds on duplicate id in static analysis of rendered HTML samples. SAP Fiori documents id prefix per app namespace. Legal discovery exports preserve fragment links to deposition exhibits.

    • Testing: Playwright getByRole preferred — getByTestId data-testid avoids id coupling.
    • i18n: id stable across locales — label text changes, id doesn't.
    • Email: Avoid id for styling — limited client support for fragments.

    Common production failures

    Component library shipped id="content" on every card — axe duplicate-id critical on PLP. Hash #terms scrolled to footer duplicate id on mobile-only terms block. React strict mode double mount exposed duplicate ids in dev mistaken for prod bug.

    • Label: for attribute pointed to wrong duplicate — PCI field mislabeled.
    • CSS: #header global style broke embedded widget also using id=header.
    • Analytics: getElementById tracked wrong button — revenue misattributed.

    Architecture review questions

    • Is every id unique in the document after hydration and dynamic inserts?
    • Are label for, aria-labelledby, and aria-describedby idrefs valid?
    • Do skip links and in-page nav target the correct id destinations?
    • Are ids stable across SSR and client renders for ARIA wiring?
    • Is id used for semantics/relationships, not primary styling hooks?
    • Do micro-frontends prefix ids to avoid collision in shared layouts?

    Hands-on project

    Add duplicate-id lint to CI on rendered HTML for top templates; fix collisions; implement skip-to-main and heading permalink ids with scroll-margin.

    • Deliverable: axe duplicate-id zero on key flows.
    • Verify: Two email fields on same page — distinct ids and labels.
    • Stretch: Namespace prefix convention doc for MFEs.

    Interview questions

    What breaks when duplicate ids exist in one document?(Advanced)

    getElementById and label for bind first match only; CSS #id applies to all but invalid HTML; ARIA IDREFs may reference wrong node; fragment navigation ambiguous. axe flags 4.1.1 violation. Fix with unique generation in lists.

    Follow-up: Are duplicate ids in shadow DOM ok?

    id vs class for CSS hooks — staff guidance?(Advanced)

    Avoid styling ids — specificity blocks overrides and prevents reuse. Reserve id for uniqueness contracts: fragments, ARIA, labels. Classes for visual patterns. Exception: third-party mount ids required by vendor.

    Follow-up: When is CSS #header acceptable?

    SPA route changes and id lifecycle?(Advanced)

    Unmount old view ids before mounting new or generate per-route prefixed ids. Persistent layout ids (main, nav) stable. Dialog ids per open instance with UUID. Test duplicate after client navigation in axe.

    Follow-up: Hash routing vs pathname for SEO?

    Try it yourself

    Edit the HTML, CSS, or JS panels — the preview updates as you type.

    Try it yourself

    Preview

    Summary

    The id attribute provides document-unique hooks for fragments, form labels, and ARIA wiring. Staff practices at Google and Stripe enforce uniqueness in CI, prefix micro-frontend ids, and never rely on duplicated or presentational id selectors.

    Ready to mark this lesson complete?Track your journey across the entire course.