Browsers repair broken markup in silence, and the repair is the bug
The HTML parser in every browser is built so it never fails. Leave out a closing div and it invents one somewhere. Put a div inside a paragraph and it ends the paragraph on the spot, then discards the real closing tag when it turns up eleven lines later. Nothing reaches the console. The page renders.
Two weeks pass. A layout collapses in one browser, a label reads out the wrong field name, or a script picks up the wrong element by id. You open the file, read it top to bottom, and it looks correct, because the mistake lives in the tree the parser built rather than the text you are looking at.
This page shows you the difference.
Markup goes on the left. The report rebuilds on the right a quarter of a second after you stop typing, and every finding carries a line, a column, the source line it came from and a note on what the browser does about it. Click a finding and the editor selects that line.
How the scan walks your document
The document is read character by character rather than through a pile of regular expressions. Tags, attributes, comments, the DOCTYPE and the raw contents of script, style, textarea and title are each handled on their own terms, so a < inside a script body never gets mistaken for a tag.
Open tags go on a stack. Closing tags pop it. Elements with optional end tags follow the same implicit rules a browser uses, so a list written as <li>One<li>Two passes without complaint, while a <div> opened inside a <p> reports the paragraph it silently ended. Anything left on the stack at the end of the file is reported as never closed, with the line where it opened.
Three depths decide how much runs, and the version buttons change the rules underneath all of them:
| Depth | What runs | When to use it |
|---|---|---|
| Structure only | DOCTYPE, html, head, body, title, tag pairing, unterminated comments | A first look at markup somebody else handed you |
| Standard | Adds unknown elements, deprecated tags and presentation attributes, repeated ids, duplicate attributes, unquoted values, nesting rules | The working default while you write a template |
| Standard and accessibility | Adds alt text, form labels, heading order, frame titles, the lang attribute, tab order, keyboard reachability | Before a page goes anywhere near production |
A fragment with no DOCTYPE, no <html> and no <body> is read as a fragment, so the five whole-document findings stay quiet. Paste a partial from a template directory and you get tag and attribute findings without five lines of noise about a missing title.
Findings people do not expect
Most of what turns up is ordinary: a typo in a tag name, a closing tag that lost its partner during an edit. Three findings surprise people often enough to name here.
- The paragraph that ends early. A paragraph holds text and inline elements. The moment a div, a table or another paragraph opens inside it, the browser closes it. Your indentation says the div is a child. The DOM says it is a sibling, and the CSS you wrote for
p .notematches nothing. - The id used twice.
getElementByIdreturns the first match, a label pointing at the id reaches the first field, and the CSS styles both. Copy and paste a block of form markup and the second copy quietly steals half the behaviour of the first. - The closing tag with no opening tag. Left behind when a wrapper gets deleted. Browsers drop it, so the page looks fine, and the next person to add a sibling element inside that region finds it landing in the wrong place.
Load the broken landing page sample and read line 12. The paragraph opens, a div follows on line 13, and the report says the paragraph ended on line 13 rather than at the </p> on line 14. Line 14 then shows a second finding, a closing tag with nothing to close, because the browser already dealt with the paragraph. One mistake, two findings, and neither of them appears in any console.
Where this fits in a working day
Hand-written pages are a small part of it. Most markup pasted in here arrives from somewhere else.
- Output from a CMS rich text field, where an editor pasted from Word and left behind spans that never close.
- An email template inherited from an agency, full of tables,
alignattributes and a DOCTYPE from 2004, checked against HTML 4.01 so the version findings match what the file claims to be. - A component handed over from a designer, pasted as a fragment, checked for label and alt problems before it goes into the codebase.
- An accessibility ticket that names a page rather than a line, where the strict depth turns the complaint into a list of files and line numbers.
When the W3C service is the better call
The Nu validator at validator.w3.org carries the full content model from the specification. It knows which elements are permitted inside which, checks attribute values against their allowed sets, and produces the answer you quote when a contract asks for conformance. Use it when being right about the spec is the point.
This page answers a narrower question, faster. It finds the mistakes that change what a browser builds, with no upload, no queue and no round trip, updating as you edit. In practice the two get used at different moments: this one while the markup is still moving, the W3C service once it stops.
Once the findings are clear, the HTML Beautifier handles indentation across a whole file, and the HTML Cleaner strips the leftovers a word processor leaves in pasted content. Stylesheets are a separate job with separate rules, so those go to the CSS Syntax Validator.
What this checker will not tell you
- The full content model is out of scope. A
<section>in a place the spec forbids parses cleanly here. The nesting rules cover the cases browsers repair, not every rule in the standard. - Attribute values are checked for quoting and repetition, not meaning.
type="emial"on an input reports nothing, and neither does a colour written as#gggggg. - Template syntax is treated as text. Blade, Twig and Handlebars expressions pass through untouched, and a conditional that opens a tag in one branch and closes it in another reports mismatched tags, because in the text in front of it the tags do not pair up.
- A clean accessibility column is not a WCAG audit. Contrast, focus order under real interaction, reading order and anything needing a rendered page sit outside a static scan. These checks catch the mistakes that are visible in markup, which is the cheap half of the work.
- Past roughly two megabytes the rescan on every keystroke starts to drag. Split the file, or check the section you are editing.
Nothing leaves the tab
The scanner, the indenter and the file picker all run in your browser. No request goes out once the page has loaded, so cut your connection and every button still works.
That matters more than it sounds for this particular tool. Markup pasted into a validator regularly carries customer names, order references, staging URLs and the odd API key sitting in a data attribute. None of it should leave your machine to find a missing div.
