Offline HTML5 validator. Validates either a full document or a smaller (incomplete) template, e.g. from an AngularJS or Vue.js component.

Learn more


Fragments and components

In addition to validating plain .html files HTML-validate can also validate sources inside .js components (or any other source) by extracting HTML fragments (transforming).

Neither .html files or component fragments need to be a complete document (e.g. doctype is not required).

Transformed sources can also be postprocessed to handle data-bindings from different frameworks, e.g. :id will still be understood the same way id would.

Learn more about transforming sources.


Many validators will behind the scene upload the markup to online services such as W3C. HTML-validate performs all validation locally, no markup leaves your machine, providing a faster and more secure response which can easily be integrated with tools and IDEs.

This means your source code is safe and is never leaked outside of your organization.

Strict parsing

When rendering a document it is useful to try to correct malformed markup but a validator should be strict. No corrections, assumptions or guessing is done. If the markup is invalid the parser will tell you so.

By ensuring the markup is strictly valid it reduces the amount of bugs where different browsers autocorrect the markup differently (this is especially true for mobile browsers).

HTML5 content model

Each element is matched against metadata for deeper logic and analysis such as whenever an element is allowed in the current context or if a required element is missing.

  • permitted ancestors and descendants
  • permitted order and occurrences
  • deprecated elements and attributes
  • flow ("block"), phrasing ("inline") etc

Learn more about writing element metadata for custom components.

Accessibility tests

Validates technical aspects of A11Y guidelines such as WCAG 2.2.


Write your own element metadata, rules and/or business logic.

Write your own shareable configurations or plugins.

Learn more about writing rules and writing plugins.


First-class support for:


Content model

    <p>Lorem ipsum dolor sit amet</p>
    <legend>Consectetur adipiscing elit</legend>

    <blink>(c) 2018 Initech</blink>

error: Element <legend> must be used before <p> in this context (element-permitted-order) at inline:4:6:
  2 |   <fieldset>
  3 |     <p>Lorem ipsum dolor sit amet</p>
> 4 |     <legend>Consectetur adipiscing elit</legend>
    |      ^^^^^^
  5 |   </fieldset>
  6 |
  7 |   <main>

error: <main> element is not permitted as a descendant of <footer> (element-permitted-content) at inline:7:4:
   5 |   </fieldset>
   6 |
>  7 |   <main>
     |    ^^^^
   8 |     <blink>(c) 2018 Initech</blink>
   9 |   </main>
  10 |

error: <blink> is deprecated (deprecated) at inline:8:6:
   6 |
   7 |   <main>
>  8 |     <blink>(c) 2018 Initech</blink>
     |      ^^^^^
   9 |   </main>
  10 |
  11 | </footer>

3 errors found.


<img src="logo.png">
<button onclick="myFunction();">Click me!</button>

<div class="field-wrapper">
  <strong>Name: </strong>
  <input type="text" name="name">
error: <img> is missing required "alt" attribute (wcag/h37) at inline:1:2:
> 1 | <img src="logo.png">
    |  ^^^
  2 | <button onclick="myFunction();">Click me!</button>
  3 |
  4 | <div class="field-wrapper">

error: <button> is missing recommended "type" attribute (no-implicit-button-type) at inline:2:2:
  1 | <img src="logo.png">
> 2 | <button onclick="myFunction();">Click me!</button>
    |  ^^^^^^
  3 |
  4 | <div class="field-wrapper">
  5 |   <strong>Name: </strong>

error: <input> element does not have a <label> (input-missing-label) at inline:6:4:
  4 | <div class="field-wrapper">
  5 |   <strong>Name: </strong>
> 6 |   <input type="text" name="name">
    |    ^^^^^
  7 | </div>

3 errors found.

Custom components

error: <my-block> element is not permitted as content under <my-inline> (element-permitted-content) at inline:2:4:
  1 | <my-inline>
> 2 |   <my-block></my-block>
    |    ^^^^^^^^
  3 |   <my-deprecated></my-deprecated>
  4 | </my-inline>

error: <my-deprecated> is deprecated: replaced with <my-other> (deprecated) at inline:3:4:
  1 | <my-inline>
  2 |   <my-block></my-block>
> 3 |   <my-deprecated></my-deprecated>
    |    ^^^^^^^^^^^^^
  4 | </my-inline>

2 errors found.