Command Palette

Search for a command to run...

Hectal
PHASE 7Advanced ~22 min· topic 6 of 8

Topic 7.6

Validating and Testing HTML

In one line

Quality comes from layers of checks: the W3C validator for correct HTML, Lighthouse and axe for automatic accessibility checks, a keyboard and screen reader pass for what tools can't judge, and the DevTools accessibility tree to see what assistive tech really gets.

Think of it like this

Getting a car ready for a long trip. A machine at the garage reads the engine's error codes in seconds (that's the automatic tools). But only a test drive tells you the seat is uncomfortable and the mirror is loose (that's manual testing). You need both, and the machine check comes first because it's cheap.

Words you'll meet

New words in this topic, in plain English. Come back here whenever one feels fuzzy.

Validator
A tool that checks your HTML against the HTML standard and lists errors and warnings.
Nu HTML Checker
The W3C's official HTML validator, at validator.w3.org/nu.
Lighthouse
A Chrome tool that scores a page for performance, accessibility, best practices and SEO.
axe-core
An open-source engine of accessibility rules, used by axe DevTools, Lighthouse and test libraries.
Automated testing
Checks a program runs for you, like axe in a test suite. Fast, but finds only some problems.
Manual testing
A person checking the page with keyboard, zoom and a screen reader. Slower, but finds what tools miss.
Rotor
VoiceOver's menu (VO+U) that lists headings, links, landmarks and form controls to jump between.
Reflow
Content re-arranging to fit a narrow or zoomed screen without sideways scrolling (WCAG 1.4.10).

Step by step

01Validate the HTML

Paste your page into validator.w3.org/nu (or run vnu.jar locally). Fix errors from the top: one early error, like an unclosed element, often causes many later ones. Here is real output for a page with two mistakes:

Nu HTML Checker outputwhole filetext
Error: Element div not allowed as child of element ul in this context. (Suppressing further errors from this subtree.)
From line 14, column 3; to line 14, column 7

Error: Duplicate ID nav.
From line 22, column 1; to line 22, column 15

Error: An img element must have an alt attribute, except under certain conditions. For details, consult guidance on providing text alternatives for images.
From line 30, column 5; to line 30, column 42

02Run Lighthouse

DevTools → Lighthouse → tick Accessibility → Analyze page load. Or from a terminal. The report lists failed audits with the elements involved, plus a list of things to check manually.

terminal
$ npx lighthouse http://localhost:3000 --only-categories=accessibility --view
── expected output ──
Runtime: ... Generating results...
Printed HTML report to ./localhost_2026-10-05_10-30-00.report.html
Opening ./localhost_2026-10-05_10-30-00.report.html

03Add axe to your tests

An automated test that fails when new violations appear stops regressions before they ship. This Playwright test checks the home page against WCAG A and AA rules.

tests/a11y.spec.tswhole filetypescript
import { test, expect } from "@playwright/test";
import AxeBuilder from "@axe-core/playwright";

test("home page has no detectable WCAG A/AA violations", async ({ page }) => {
  await page.goto("http://localhost:3000/");
  const results = await new AxeBuilder({ page })
    .withTags(["wcag2a", "wcag2aa", "wcag21a", "wcag21aa", "wcag22aa"])
    .analyze();
  expect(results.violations).toEqual([]);
});

04Do the keyboard and zoom pass

Tab from the address bar to the footer and back. Then zoom to 400% (or set the window to 320 px wide): text should wrap, menus should collapse, nothing should be clipped.

05Listen with a screen reader

Start NVDA or VoiceOver. Open the headings list (NVDA+F7, or VO+U on Mac): does it read like a table of contents? Jump between landmarks. Tab into the form and submit it empty: are errors announced?

Listen with a screen readerdiagram
Rendering diagram…

06Inspect the accessibility tree

When something sounds wrong, select the element in DevTools and read the Accessibility pane: Name, Role, and properties like focusable, required, invalid, expanded. The "Name" row shows which source (label, aria-label, contents) produced it.

Try it yourself

  1. 1

    Make it valid

    In the first example, change the div inside the paragraph to a span and move the div in the list into an li. Predict the three log lines before running. (1 paragraph, true because the span class="box" now stays inside it, and LI, LI.)

  2. 2

    Clean the lint

    In the second example, fix the HTML so the log shows a clean outline (H1, then H2s with H3s under them), no duplicate ids ([]) and lang: en.

  3. 3

    Audit a real page

    Open any site you've built (or a favourite site), run Lighthouse's accessibility audit and the axe DevTools extension. Compare: do they report the same problems? Then pick one failure and find the element in the Accessibility pane.

Code & diagrams

Invalid HTML gets silently rewritten New tab

A `<p>` can't contain a `<div>`, so the parser closes the paragraph before the div, and the stray `</p>` creates a second, empty paragraph. The `div` in the `ul` is kept but is invalid: a screen reader may count the list wrongly. The validator reports both.

Preview

Press Run to see the page.

Console

Nothing logged yet.

Expected console output

paragraphs written: 1, paragraphs in the DOM: 2
div is inside the p? false
children of ul: DIV, LI
A mini linter: headings, ids and lang New tab

Real tools check hundreds of rules like these. Fix the HTML until there are no jumps, no duplicates and a language is set.

Preview

Press Run to see the page.

Console

Nothing logged yet.

Expected console output

H1 Recipes
    H3 Breakfast  <- skips a level
  H2 Lunch
      H4 Soups  <- skips a level
duplicate ids: [ 'note' ]
lang: (missing)
Testing layers: what each catchesdiagram
Rendering diagram…

Break it on purpose

Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.

Break #1

Trust the Lighthouse score

Ship a page that scores 100 in Lighthouse accessibility, with alt="image" on every product photo and a menu that only opens on mouse hover.

terminal
$ Lighthouse → Accessibility
── what you'll see ──
100 — but screen reader users hear "image" for every product, and keyboard users can't open the menu

Break #2

Duplicate an id

Copy a form field block and forget to change id="email" and for="email" in the copy.

terminal
$ click the second label
── what you'll see ──
Focus jumps to the first email field; the validator says "Duplicate ID email."

Myth vs fact

Myth

A Lighthouse score of 100 means the page is accessible.

Fact

It means none of its automatic audits failed. Many WCAG criteria can only be checked by a person.

Myth

If it renders correctly, the HTML is valid.

Fact

Browsers repair errors silently. The DOM may differ from your source, which breaks selectors, scripts and accessibility.

Myth

You need to be an expert screen reader user to test.

Fact

A few keys (headings list, landmarks, Tab, arrows) catch most big problems. Expert audits and testing with disabled users come on top.

Pro corner

Extra depth for experienced readers. New to this? Skip it for now and come back later.

  • ▸

    Validation is not an end in itself (WCAG 2.2 removed 4.1.1 Parsing), but the errors that matter are real bugs: duplicate ids break label and ARIA references, bad nesting changes the DOM and the accessibility tree, and unknown attributes are often typos (aria-lable). Lint in the editor (html-validate, eslint-plugin-jsx-a11y for React) to catch them before review.

  • ▸

    axe-core is designed for zero false positives: when it's unsure, it reports "needs review" (incomplete) instead of a violation. In CI, fail on violations and log incompletes for humans.

  • ▸

    Chrome's accessibility tree is built lazily and cached; heavy DOM changes cause tree updates that cost time on huge pages. Very large DOMs (Lighthouse warns above about 1,400 elements) slow both rendering and assistive tech.

  • ▸

    Testing with actual disabled users finds problems no checklist does (confusing wording, tiring flows). The W3C WAI site has guidance on involving users, and WebAIM's screen reader survey shows which screen reader and browser combinations to prioritise.

Remember this

  1. 1

    Validation checks your HTML against the HTML standard. The W3C Nu HTML Checker (validator.w3.org/nu) accepts a URL, an uploaded file or pasted code and lists errors (rule breaks, like a div inside a ul, a duplicate id, a missing alt) and warnings (allowed but probably wrong, like a redundant role). Browsers repair invalid HTML silently (Topic 0.4), so a page can look fine while its DOM is different from what you wrote, which confuses CSS, JavaScript and assistive tech.

  2. 2

    Lighthouse, built into Chrome DevTools (the Lighthouse panel) and available as a command-line tool, audits a page for performance, accessibility, best practices and SEO, giving each a score from 0 to 100. Its accessibility audits are a subset of axe-core. A score of 100 means no automatically detectable problems were found, not that the page is accessible.

  3. 3

    axe (axe-core, by Deque) is the most widely used accessibility rules engine. Use it as the free axe DevTools browser extension while building, and in automated tests (@axe-core/playwright, jest-axe, Cypress plugins) so every pull request is checked. Each finding has a rule id (like image-alt, label, color-contrast, button-name), the failing element, the WCAG criterion and a fix. Other tools: WAVE (WebAIM's visual overlay), pa11y (command line) and html-validate (a linter for HTML source).

  4. 4

    Automated tools find only part of the problem. Studies differ on how much: a UK government test in 2017 found that the tools caught roughly 30–40% of deliberately planted barriers, and Deque reports that automated tests found about 57% of issues by volume in its audits. Tools can tell that an alt exists, but not whether it's right; that focus is visible, but not whether the order makes sense. Manual testing fills the gap.

  5. 5

    The five-minute manual test: (1) keyboard: Tab through everything, use Enter, Space, arrows and Esc (Topic 7.3); (2) zoom the page to 200% and 400%: nothing should be cut off and you shouldn't need to scroll sideways at a 320 px wide view (WCAG 1.4.10 Reflow); (3) screen reader quick pass: list the headings and landmarks, tab through the form, and listen to what's announced; (4) check images and links out of context: do the alt texts and link texts make sense on their own?; (5) turn off CSS or view in Reader mode: does the order still make sense?

  6. 6

    Screen readers to test with: NVDA (free, Windows; the NVDA key is Insert; H next heading, D next landmark, K next link, F next form field, NVDA+F7 lists elements), VoiceOver (built into macOS and iOS; Cmd+F5 toggles it on Mac; the VO keys are Ctrl+Option; VO+U opens the rotor of headings, links and landmarks), Narrator (Windows, Ctrl+Win+Enter) and TalkBack (Android; swipe right to move, double-tap to activate). The most common pairings in WebAIM's screen reader survey are NVDA or JAWS with Chrome on Windows, and VoiceOver with Safari on Apple devices.

  7. 7

    DevTools shows what assistive tech gets. In Chrome: Elements → Accessibility pane lists the selected node's computed name (and where it came from), role, and states; the "Enable full-page accessibility tree" option lets you switch the whole Elements panel to the accessibility tree. The Rendering panel can emulate vision deficiencies (blurred vision, reduced contrast, protanopia, deuteranopia, tritanopia, achromatopsia) and prefers-reduced-motion. The colour picker in the Styles pane shows the contrast ratio with AA/AAA ticks. Firefox's Accessibility Inspector can "Check for issues" and "Show Tabbing Order" as numbered overlays.

Explain it without notes

01

Why validate HTML if browsers display invalid HTML anyway?

02

What can automated accessibility tools catch, and what can't they? How do you test the rest?

03

How would you add accessibility checks to a team's development process?

04

What does the DevTools accessibility pane show, and when do you use it?

Practice

01

Write a Playwright test that loads /signup and fails if axe finds any WCAG A or AA violations.

02

This HTML has three validation errors. List them and write the fixed version: <ul><div><li>One</li></div></ul><img src="a.png"><label for="x">Name</label><input id="y">

Trade-offs

  • ↔

    Failing CI on every axe violation keeps quality high but can block urgent releases on legacy pages; many teams fail on new violations only and burn down the existing ones over time.

  • ↔

    Manual screen reader testing is slow, so do it on templates and components (once per pattern) rather than on every page.

Done when you can

  • I can validate a page with the W3C Nu HTML Checker and fix its errors.

  • I can run Lighthouse and axe and read their findings.

  • I can add an axe check to an automated test.

  • I can do a keyboard, zoom and quick screen reader pass.

  • I can read the name, role and states in the DevTools Accessibility pane.