gizmobench

HTML Validator

Paste markup and see what it breaks, with the line and the column on every problem and the exact rule that caught it. What is different here is the list: all 25 rules are printed under the tool with an id, a severity and a sentence saying what each one wants, and the ones your current mode and rule set do not run are greyed rather than hidden. It is an authoring lint, not a conformance certificate: passing means your markup broke none of the rules that were switched on. Fragment mode checks a block you are working on and leaves out the five checks that need a whole page around them; document mode adds the doctype, the language, the title, the character encoding and id references. Nothing is uploaded, nothing is run, and a script element is only ever text to the scanner.

diagnostics2 problems
  • 4:3errorimg-altThis <img> has no alt attribute, so a screen reader reads out the file name instead. Describe the image with alt="...", or write alt="" when it is decorative.
  • 5:7errorpermitted-content<p> is not allowed inside <ul>, which was opened at 5:3. A <ul> may contain <li>. Move this element, or wrap it in one of those.
Errors
2
Warnings
0
Mode
Rules

2 errors and 0 warnings in 6 lines, each with its line and column.

Source, with each problem marked

The lines the problems point at, exactly as you pasted them, with the span each rule read underlined.

4 <img src="a.png">
5 <ul><p>x</p></ul>
  • Missing altimg tag
    error at 1:1
  • Wrong nestingp inside ul
    error at 1:5
  • Clean fragmentvalid markup
    no problems

The rules this page checks

All 25 of them, every one of which can be reported by name. 20 run in fragment mode with the recommended set, and the rest are greyed below. 5 of those need the whole page around them, so fragment mode leaves them out rather than guessing: doctype, charset, missing-reference, html-lang, document-title.

  • unterminated-tagerror · structureEvery tag, comment and raw text element is closed before the end of the file.
  • stray-end-tagerror · structureAn end tag has a matching element open above it.
  • close-ordererror · structureElements close in the order they opened, so no two of them cross.
  • unclosed-elementerror · structureAn element whose end tag is required has one.
  • void-end-tagerror · structureVoid elements such as img and br are not given an end tag.
  • self-closing-tagwarning · structureA trailing slash is not used on an ordinary HTML element, where it closes nothing.
  • permitted-contenterror · structureAn element sits in a parent that is allowed to contain it.
  • raw-characterswarning · structureA literal < or a bare & in text is written as a character reference.
  • doctypenot in this modeA document opens with the HTML doctype before anything else.
  • charsetnot in this modeA document declares its character encoding in the head.
  • duplicate-iderror · attributesNo id value is used on more than one element.
  • duplicate-attributeerror · attributesNo attribute is written twice on the same tag.
  • attribute-quoteswarning · attributesAttribute values are quoted.
  • element-casewarning · attributesElement names are written in lower case.
  • attribute-casewarning · attributesAttribute names are written in lower case.
  • deprecated-elementwarning · attributesNo element that HTML has removed is used.
  • deprecated-attributewarning · attributesNo presentational attribute that HTML has removed is used.
  • missing-referencenot in this modeAn attribute that names an id points at an element that exists.
  • img-alterror · accessibilityEvery img carries an alt attribute, empty when the image is decorative.
  • control-labelerror · accessibilityEvery input, select and textarea has a label, an aria-label or an aria-labelledby.
  • heading-orderwarning · accessibilityHeading levels go down one at a time, so none is skipped.
  • empty-headingwarning · accessibilityEvery heading has text in it, or an image with alt text.
  • iframe-titlewarning · accessibilityEvery iframe carries a title attribute naming what it holds.
  • html-langnot in this modeA document declares its language on the html element.
  • document-titlenot in this modeA document has a title element with text in it.
What a clean result means. It means your markup broke none of the rules in the list above, at the line and column of every check. It does not mean the document conforms to the HTML standard: a conformance checker reads the full content model of every element, and this reads the list. Use it while you write, and the W3C service before you publish something that has to be exact.

Up to 1,000,000 characters in one pass, read here in your browser with nothing uploaded and no account. Open file reads a file from your device in the same way. Your markup is never run: a script element is text to the scanner, and no src, href or onerror is ever opened or evaluated. The mode, the rule set and the draft are kept in this browser alone, drafts up to 200,000 characters, and the Start over control above the tool forgets them.

Accuracy. Checks your markup against the rule set named on the page, and every problem carries its line and column. Passing here means it broke none of those rules: it is an authoring lint, not a W3C conformance certificate, and the rule list is published so you know what was checked.

Common questions

Is this the same as the W3C validator?
No, and the difference is worth knowing. The W3C service works from the full content model of every element in the HTML standard, so it can tell you about cases no short list covers. This page runs a fixed list of 25 authoring rules, printed under the tool, and reports only what that list covers. A clean result here means your markup broke none of those rules: it is the check you want while you are writing, and it is not a conformance certificate. For something that has to be exact before it is published, run the W3C service as well.
What does it actually check?
Three groups. Structure: tags that are never closed, end tags with nothing open above them, elements that cross each other, an end tag on a void element such as img or br, a trailing slash that closes nothing in HTML, content in a parent that cannot hold it (a paragraph inside a list, a table cell outside a row, a button inside a link), and a literal < or a bare & in text. Attributes: a duplicate id, the same attribute twice on one tag, an unquoted value, mixed-case element and attribute names, and elements and attributes HTML has removed such as center, font, align and bgcolor. Accessibility: an img with no alt, an input, select or textarea with no label, a skipped heading level, an empty heading, and an iframe with no title. Document mode adds the doctype, the lang attribute on html, a non-empty title, a declared character encoding and references such as label for that point at an id no element has.
What is the difference between fragment and document mode?
Fragment mode is for a block you are working on: a card, a table, a form, the output of a template. Five of the checks only make sense when the whole page is in view, so fragment mode turns them off rather than telling you that your list item has no doctype. Those five are the doctype, the language on the html element, the title, the character encoding, and whether an attribute that names an id points at one that exists. They stay in the published list, marked as not running, so you can always see what a fragment was not checked for. Document mode with the recommended set runs every one of them.
Why is a paragraph not allowed inside a list?
Because a ul or an ol may only contain li, script and template elements. A browser will not refuse it: it keeps the paragraph inside the list, and a screen reader then announces a list whose items do not match what is in it, while your list styling applies to something that was never an item. In a table the parser goes further and moves stray text out of the table altogether, which is why a table that looked right in your editor renders with a line of text sitting above it. The fix in both cases is to put the content in an element that is allowed to hold it, an li or a td. The same rule catches a td outside a tr, an option outside a select, a figcaption outside a figure, and a link, a button or a form nested inside another of its own kind. Three parents are left alone by this rule because the tool cannot know what they hold: a template, whose content model is anything at all, a custom element with a dash in its name, and the inside of an svg or a MathML block, which have models of their own.
Does it run the JavaScript in the page I paste?
No. Nothing pasted here is ever evaluated. The scanner reads the markup as characters: a script element is a string of text it counts and skips, an onerror attribute is a string of text, and no src, href or link is ever opened. There is no network request of any kind, so a page you were sent to inspect can be checked here without it doing anything at all.
Is my HTML uploaded anywhere?
No. The whole lint runs in your own browser, which matters when the markup is a client's page or an internal template. There is no account, no sign-up and no upload, and Open file reads a file from your device in the same local way. Your draft is remembered on this device alone so it is still there when you come back: up to 200,000 characters of it is written to local storage, a longer paste is still checked in full but is not stored, and the Start over button above the tool forgets the draft along with your mode and rule set.
Can I export the result?
Yes. Copy report and Download both produce the same plain-text report: the mode and rule set, the counts, every listed problem with its line, column, severity, rule id and message, then the full list of rules that were checked and the ones this mode left out. It is written to be pasted into a pull request or an issue, where the rule ids mean the reader can see what was and was not looked at.
How much HTML can I check at once?
Up to 1,000,000 characters in a single pass, which is a large page several times over. Past that the tool says how large your paste is and how large it may be, and checks nothing until you cut it down. It never truncates: a validator that silently dropped the end of your document would tell you it was clean when it had not looked. The counts above the list are always of everything found, and where a page has more problems than the list prints, the page says so and gives the true number.

Checks your markup against the rule set named on the page, and every problem carries its line and column. Passing here means it broke none of those rules: it is an authoring lint, not a W3C conformance certificate, and the rule list is published so you know what was checked.