Getting started

HTML-validate is an offline HTML5 validator.


Install using npm:

npm install --save-dev html-validate

Create a configuration file:

  "extends": ["html-validate:recommended"]

Run with:

npm exec html-validate yourfile.html


Configuration can be added to:

ESM configuration files are not currently supported.

For json the JSON schema can optionally be used:

  "$schema": "",
  "extends": ["html-validate:recommended"],

For js and cjs the defineConfig(..) helper can optionally be used to assist the IDE with type-checking and documentation:

import { defineConfig } from "html-validate";

module.exports = defineConfig({
  extends: ["html-validate:recommended"],

Configuration files will be searched from the target file and up until either no more parent folders exist or "root": true is found.


Configuration can be extended from bundled preset or shareable configurations.

  "plugins": ["my-plugin"],
  "extends": [
    /* bundled preset */

    /* npm package */

    /* preset "recommended" from "my-plugin" */

    /* local file */

A list of bundled presets is available at the preset list. By default html-validate:recommended is used.

When using NPM packages or files each must be resolvable with require(..) and export a valid configuration object. Plugins may create configuration presets by exposing one or more preset in the plugin declaration.


  "rules": {
    "some-rules": "severity",
    "other-rule": ["severity", { "option": true }]

Severity can be one of:

Some options takes optional parameters when using the form ["severity", OPTIONS].

See Available rules for a list of all built-in rules and options.


For proper validation some metadata for each element is required, detailing in which context it can be used, allowed/disallowed attributes, etc. If elements is not specified it defaults to ["html5"] which is a bundled collection for all HTML5 elements.

  "elements": [
      /* inline metadata */

Each entry will try to load metadata from (search in following order):

  1. Named bundled metadata.
  2. NPM package with the same name.
  3. A local file, json or js, resolvable by require(..). Path is relative to the configuration file.

Loading native ESM is not supported yet (see issue #125) and must be transpiled to commonjs before usage.

An object can also be passed with inline metadata but it is highly recommended to write it to a separate file.

See elements metadata for details about writing your own metadata.


List of extra plugins to load. Plugins can contain additional rules, predefined configurations and transformers.

Can be either a NPM package or relative path to a local file, i.e. when writing custom rules inside the repository. Must be resolvable by require(..).

See writing plugins for details about creating your own plugins.

  "plugins": ["my-awesome-plugin", "./local-plugin"]

Loading native ESM is not supported yet (see issue #125) and must be transpiled to commonjs before usage.

Since version 7.17.0, if you are using javascript configuration or API you can also import or define plugins inline:

const { defineConfig } = require("html-validate");

module.exports = defineConfig({
  plugins: [
      name: "my-awesome-plugin",
      /* ... */


Transform input files to extract HTML chunks, e.g. extract templates from javascript sources. See transformers for details.

  "transform": {
    "^.*\\.vue$": "html-validate-vue"

This will transform *.vue with the html-validate-vue NPM package. Use a relative path to use a local script (use <rootDir> to refer to the path to package.json, e.g. <rootDir>/my-transformer.js).


By default, configuration is search in the file structure until the root directory (typically /) is found:

By setting the root property to true the search is stopped. This can be used to prevent searching from outside the project directory or to use a specific configuration for a specific directory without loading project configuration.

For instance, if /home/project/.htmlvalidate.json contains:

  "root": true

Only the following files would be searched:

This also affects CLI --config and the API, e.g. when using --config with a configuration using "root": true will prevent any additional files to be loaded.

Inline configuration

Configuration can be changed inline using directive of the form:

<!-- [html-validate-ACTION OPTIONS -- COMMENT] -->

ACTION is an action such as enable, disable etc and OPTIONS is arguments to the action. Comment is optional but encouraged.

Multiple rules can be enabled/disabled at once by using a comma-separated list:

<!-- [html-validate-disable-next void-style, deprecated -- disable both rules] -->

Comments can be entered using both -- and : as delimiter:

<!-- [html-validate-disable-next deprecated -- justification for disabling] -->
<blink>Blinking text</blink>
<!-- [html-validate-disable-next deprecated: justification for disabling] -->
<blink>Blinking text</blink>


<!-- [html-validate-enable element-permitted-content] -->

Enables a rule. If the severity is set to off it will be raised to error, i.e a previously disabled warning will remain a warning after enabling it again.


<!-- [html-validate-disable deprecated] -->

Disable a rule for the rest of the file or until re-enabled using enable directive.


<!-- [html-validate-disable-block attribute-allowed-values] -->

Disables a rule for a block of elements. All siblings and descendants following the directive will not trigger any errors.

  <button type="foo">Invalid button</button>
  <!-- [html-validate-disable-block attribute-allowed-values -- will be disabled until the parent div is closed] -->
  <button type="bar">Invalid but ignored</button>
  <button type="baz">Still ignored</button>
<button type="spam">Another invalid</button>
error: Attribute "type" has invalid value "foo" (attribute-allowed-values) at inline:2:17:
  1 | <div>
> 2 |   <button type="foo">Invalid button</button>
    |                 ^^^
  3 |   <!-- [html-validate-disable-block attribute-allowed-values -- will be disabled until the parent div is closed] -->
  4 |   <button type="bar">Invalid but ignored</button>
  5 |   <button type="baz">Still ignored</button>

error: Attribute "type" has invalid value "spam" (attribute-allowed-values) at inline:7:15:
  5 |   <button type="baz">Still ignored</button>
  6 | </div>
> 7 | <button type="spam">Another invalid</button>
    |               ^^^^

2 errors found.


<!-- [html-validate-disable-next deprecated] -->

Disables the rule for the next element.

<!-- [html-validate-disable-next deprecated -- the next occurrence will not trigger an error] -->
<blink>This will not trigger an error</blink>
<blink>But this line will</blink>
error: <blink> is deprecated (deprecated) at inline:3:2:
  1 | <!-- [html-validate-disable-next deprecated -- the next occurrence will not trigger an error] -->
  2 | <blink>This will not trigger an error</blink>
> 3 | <blink>But this line will</blink>
    |  ^^^^^

1 error found.

Ignoring files

.htmlvalidateignore file

The .htmlvalidateignore file works similar to .gitignore, i.e. the file should contain a list of file patterns to ignore.

Similar to .gitignore if a line starts with / it matches from the current directory only, e.g /foo.html matches only foo.html in the current directory but not src/foo.html.