Vize

HTML rules

Every rule on this page includes its purpose, prerequisites, configuration, and complete Bad/Good examples. Highlighted lines show what changes; copying an example gives you the complete source. Each rule also states its current support limits.

Rule Examples Purpose
html/deprecated-attr Bad · Good Disallow deprecated HTML attributes
html/deprecated-element Bad · Good Disallow deprecated HTML elements
html/id-duplication Bad · Good Disallow duplicate element IDs
html/no-consecutive-br Bad · Good Disallow consecutive <br> elements
html/no-dupe-style-properties Bad · Good Disallow duplicate properties in inline style attributes
html/no-duplicate-class Bad · Good Disallow duplicate class names in a static class attribute
html/no-duplicate-dt Bad · Good Disallow duplicate <dt> names in <dl>
html/no-empty-palpable-content Bad · Good Disallow empty elements that expect visible content
html/require-datetime Bad · Good Require datetime attribute on <time> element

All rules · Rule Options · ESLint migration map · Project checks · Attributes across components

html/deprecated-attr

Disallow deprecated HTML attributes

Bad · Good

Default severity: warning
Presets: happy-path, nuxt, ecosystem, opinionated
Automatic fix: None; review the suggested change
Applies to: Vue SFC templates and blocks, with script context where the rule requires it
Options: No rule-specific options. Severity and preset selection are configurable.

Configuration (Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  lint: {
    vize: {
      "preset": "incremental",
      "rules": {
        "html/deprecated-attr": "warn"
      }
    },
  },
});
vp run lint

Bad

The paragraph uses the deprecated presentational align attribute.

<template>
<p align="center">Notice</p>
</template>

Good

The class and text-align: center declaration express the alignment through CSS.

<template><p class="notice">Notice</p></template>
<style scoped>.notice { text-align: center; }</style>

Good avoids this rule's finding under the configuration above; other rules may still report diagnostics.

Implementation · All rules

html/deprecated-element

Disallow deprecated HTML elements

Bad · Good

Default severity: warning
Presets: happy-path, nuxt, ecosystem, opinionated
Automatic fix: None; review the suggested change
Applies to: Vue SFC templates and blocks, with script context where the rule requires it
Options: No rule-specific options. Severity and preset selection are configurable.

Configuration (Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  lint: {
    vize: {
      "preset": "incremental",
      "rules": {
        "html/deprecated-element": "warn"
      }
    },
  },
});
vp run lint

Bad

The center element uses a deprecated HTML presentation element.

<template>
  <center>Profile</center>
</template>

Good

A section and a styling class replace the deprecated element while preserving the content.

<template>
  <section class="profile">Profile</section>
</template>

Good avoids this rule's finding under the configuration above; other rules may still report diagnostics.

Implementation · All rules

html/id-duplication

Disallow duplicate element IDs

Bad · Good

Default severity: error
Presets: essential, happy-path, nuxt, ecosystem, opinionated
Automatic fix: None; review the suggested change
Applies to: Vue SFC templates and blocks, with script context where the rule requires it
Options: No rule-specific options. Severity and preset selection are configurable.

Configuration (Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  lint: {
    vize: {
      "preset": "incremental",
      "rules": {
        "html/id-duplication": "error"
      }
    },
  },
});
vp run lint

Bad

Both the input and help paragraph declare id="email", so the label target is ambiguous.

<template>
  <label for="email">Email</label>
  <input id="email" />
  <p id="email">Required</p>
</template>

Good

The input keeps email; the help paragraph uses email-help, and aria-describedby refers to that distinct ID.

<template>
  <label for="email">Email</label>
  <input id="email" aria-describedby="email-help" />
  <p id="email-help">Required</p>
</template>

Good avoids this rule's finding under the configuration above; other rules may still report diagnostics.

Implementation · All rules

html/no-consecutive-br

Disallow consecutive <br> elements

Bad · Good

Default severity: warning
Presets: happy-path, nuxt, ecosystem, opinionated
Automatic fix: None; review the suggested change
Applies to: Vue SFC templates and blocks, with script context where the rule requires it
Options: No rule-specific options. Severity and preset selection are configurable.

Configuration (Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  lint: {
    vize: {
      "preset": "incremental",
      "rules": {
        "html/no-consecutive-br": "warn"
      }
    },
  },
});
vp run lint

Bad

Two consecutive break elements create spacing between blocks inside a single paragraph.

<template>
  <p>First line<br /><br />Second block</p>
</template>

Good

Separate paragraphs express the two content blocks without repeated break elements.

<template>
  <p>First line</p>
  <p>Second block</p>
</template>

Good avoids this rule's finding under the configuration above; other rules may still report diagnostics.

Implementation · All rules

html/no-dupe-style-properties

Disallow duplicate properties in inline style attributes

Bad · Good

Default severity: warning
Presets: nuxt, opinionated
Automatic fix: None; review the suggested change
Applies to: Vue SFC templates and blocks, with script context where the rule requires it
Options: No rule-specific options. Severity and preset selection are configurable.

Configuration (Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  lint: {
    vize: {
      "preset": "incremental",
      "rules": {
        "html/no-dupe-style-properties": "warn"
      }
    },
  },
});
vp run lint

Bad

Each static style repeats one property; margin and MARGIN also count as the same property.

<template>
  <div style="color: red; color: blue">text</div>
  <div style="margin: 0; MARGIN: 1px">text</div>
</template>

Good

The static style uses distinct color and background properties. Dynamic style bindings are outside this static-attribute check.

<template>
  <div style="color: red; background: blue">text</div>
  <div :style="{ color: a, color: b }">text</div>
</template>

Good avoids this rule's finding under the configuration above; other rules may still report diagnostics.

Implementation · All rules

html/no-duplicate-class

Disallow duplicate class names in a static class attribute

Bad · Good

Default severity: warning
Presets: nuxt, opinionated
Automatic fix: None; review the suggested change
Applies to: Vue SFC templates and blocks, with script context where the rule requires it
Options: No rule-specific options. Severity and preset selection are configurable.

Configuration (Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  lint: {
    vize: {
      "preset": "incremental",
      "rules": {
        "html/no-duplicate-class": "warn"
      }
    },
  },
});
vp run lint

Bad

The static class list repeats the btn token.

<template>
  <div class="btn btn primary">click</div>
</template>

Good

The class list keeps one btn token and the distinct primary token.

<template>
  <div class="btn primary">click</div>
</template>

Good avoids this rule's finding under the configuration above; other rules may still report diagnostics.

Implementation · All rules

html/no-duplicate-dt

Disallow duplicate <dt> names in <dl>

Bad · Good

Default severity: warning
Presets: happy-path, nuxt, ecosystem, opinionated
Automatic fix: None; review the suggested change
Applies to: Vue SFC templates and blocks, with script context where the rule requires it
Options: No rule-specific options. Severity and preset selection are configurable.

Configuration (Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  lint: {
    vize: {
      "preset": "incremental",
      "rules": {
        "html/no-duplicate-dt": "warn"
      }
    },
  },
});
vp run lint

Bad

The same definition list repeats the API term for two descriptions.

<template>
  <dl>
    <dt>API</dt>
    <dd>Public interface</dd>
    <dt>API</dt>
    <dd>Internal service</dd>
  </dl>
</template>

Good

One API term is followed by both descriptions, avoiding the repeated term.

<template>
  <dl>
    <dt>API</dt>
    <dd>Public interface</dd>
    <dd>Internal service</dd>
  </dl>
</template>

Good avoids this rule's finding under the configuration above; other rules may still report diagnostics.

Implementation · All rules

html/no-empty-palpable-content

Disallow empty elements that expect visible content

Bad · Good

Default severity: warning
Presets: happy-path, nuxt, ecosystem, opinionated
Automatic fix: None; review the suggested change
Applies to: Vue SFC templates and blocks, with script context where the rule requires it
Options: See typed options and defaults.

Configuration (Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  lint: {
    vize: {
      "preset": "incremental",
      "rules": {
        "html/no-empty-palpable-content": "warn"
      }
    },
  },
});
vp run lint

Bad

The paragraph, list item, and table cell all have empty palpable content.

<template>
  <p></p>
  <li></li>
  <td></td>
</template>

Good

Text fills the paragraph, interpolation supplies the list item, and aria-label explicitly names the otherwise empty cell.

<template>
  <p>Overview</p>
  <li>{{ item.label }}</li>
  <td aria-label="No value"></td>
</template>

Good avoids this rule's finding under the configuration above; other rules may still report diagnostics.

Implementation · All rules

html/require-datetime

Require datetime attribute on <time> element

Bad · Good

Default severity: warning
Presets: happy-path, nuxt, ecosystem, opinionated
Automatic fix: None; review the suggested change
Applies to: Vue SFC templates and blocks, with script context where the rule requires it
Options: No rule-specific options. Severity and preset selection are configurable.

Configuration (Vite+)

import { defineConfig } from "@vizejs/vite-plugin/vite-plus";

export default defineConfig({
  lint: {
    vize: {
      "preset": "incremental",
      "rules": {
        "html/require-datetime": "warn"
      }
    },
  },
});
vp run lint

Bad

The time element contains a human-readable date but no machine-readable datetime value.

<template>
  <time>May 13, 2026</time>
</template>

Good

datetime="2026-05-13" supplies the corresponding machine-readable date.

<template>
  <time datetime="2026-05-13">May 13, 2026</time>
</template>

Good avoids this rule's finding under the configuration above; other rules may still report diagnostics.

Implementation · All rules