Validate Your HTML
This is part 1 of the Accessibility Testing series. HTML validation comes first because invalid markup can cause automated tools to miss issues or report false positives — and it affects how assistive technologies interpret your page.
Why valid HTML matters
Assistive technologies rely on the browser’s DOM to build the accessibility tree. When your HTML is invalid, the browser has to guess how to parse it — and different browsers guess differently. The result: screen readers may skip content, announce elements incorrectly, or miss interactive controls entirely.
Invalid HTML also causes SSR (Server-Side Rendering) bugs and unexpected UX problems. For example:
- Nesting a
<button>inside an<a>creates two nested interactive elements. Screen readers may only announce the outer one, or create separate tab stops that make no sense to keyboard users. - Nesting a
<div>inside a<p>is invalid — browsers silently close the outer<p>and create unexpected DOM structure. In frameworks like React, Vue, or Astro this can also cause hydration mismatches. - Nesting a
<p>inside another<p>has the same problem — the browser auto-closes the outer paragraph, splitting your content in ways you won’t see visually but screen readers will.
A common e-commerce example: product cards wrapped in a link
Wrapping product cards in a link is tempting, but be aware — it might be ILLEGAL 🚨
A pattern you’ll see often in e-commerce: wrapping an entire product card in an <a> tag. This becomes a problem when the card contains other interactive elements — links, buttons, checkboxes, tooltips. Nested links are illegal per the HTML spec, and nesting other interactive elements inside a link leads to invalid HTML and unpredictable browser behavior. If you’re using SSR, this can also trigger hydration warnings.
For a deeper look at how browsers handle these situations, see Vadim Makeev’s article Jumping HTML Tags.
Not sure if one element can be nested inside another? Use caninclude — a quick tool that tells you whether a specific HTML nesting is valid.
How to validate
Use the W3C Markup Validation Service to check your page or component HTML. You can validate by:
- URL — paste the live URL of your page
- File upload — upload the HTML file
- Text input — paste your HTML snippet directly
The validator will flag both errors (must fix) and warnings (should consider). For example:
- Warning: Consider adding a
langattribute to the<html>start tag to declare the language of this document. - Error: The element
buttonmust not appear as a descendant of theaelement.
Validation in your development workflow
You don’t have to leave your editor to validate. There are tools that catch HTML issues as you code:
- html-validate — an npm linter for HTML that can run in CI or as a pre-commit hook
- eslint-plugin-jsx-a11y — ESLint plugin that catches accessibility and markup issues in JSX/TSX
- Browser extensions — the W3C Nu Html Checker also offers a browser bookmarklet for quick checks
Catching issues during development is always cheaper than finding them in production.
What to look for
Focus on fixing:
- Invalid nesting — elements inside parents they don’t belong in (
<button>in<a>,<div>in<p>) - Missing required attributes —
alton images (WCAG 1.1.1),langon<html>(WCAG 3.1.1) - Duplicate
idattributes — these break label associations and anchor links - Unclosed elements — can cause the browser to build a different DOM than you intended
See also: Run automated tools