Vize

Accessibility structure

Use these rules to review how a page is organized and described: headings, landmarks, labels, frames, media, and focusable interactive elements. Start here when a component adds a new section, embedded frame, image, or media player.

For example, heading-levels provides a concrete heading-order check. Compare its Bad/Good examples, enable the rule using its configuration, and run vp run lint. For the full set, follow the accessibility guide.

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
a11y/heading-has-content Bad · Good Require heading elements to have accessible content
a11y/heading-levels Bad · Good Disallow skipping heading levels
a11y/iframe-has-title Bad · Good Require iframe elements to have a title attribute
a11y/img-alt Bad · Good Require alt attribute on images for accessibility
a11y/interactive-supports-focus Bad · Good Require interactive role elements to be focusable
a11y/label-has-for Bad · Good Require labels to have associated form controls
a11y/landmark-roles Bad · Good Validate landmark role placement and uniqueness
a11y/media-has-caption Bad · Good Require media elements to have captions

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

a11y/heading-has-content

Require heading elements to have accessible 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: 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": {
        "a11y/heading-has-content": "warn"
      }
    },
  },
});
vp run lint

Bad

The h2 contributes a heading level but has no heading content.

<template>
  <h2></h2>
</template>

Good

Billing settings supplies the content of the existing level-two heading.

<template>
  <h2>Billing settings</h2>
</template>

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

Implementation · All rules

a11y/heading-levels

Disallow skipping heading levels

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": {
        "a11y/heading-levels": "warn"
      }
    },
  },
});
vp run lint

Bad

The heading sequence jumps directly from h1 to h3, skipping level two.

<template>
  <h1>Account</h1>
  <h3>Billing</h3>
</template>

Good

Changing the billing heading to h2 preserves a consecutive heading hierarchy.

<template>
  <h1>Account</h1>
  <h2>Billing</h2>
</template>

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

Implementation · All rules

a11y/iframe-has-title

Require iframe elements to have a title attribute

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": {
        "a11y/iframe-has-title": "warn"
      }
    },
  },
});
vp run lint

Bad

The checkout frame has a source URL but no title describing the embedded content.

<template>
  <iframe src="/checkout"></iframe>
</template>

Good

title="Checkout preview" names the content of that frame.

<template>
  <iframe src="/checkout" title="Checkout preview"></iframe>
</template>

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

Implementation · All rules

a11y/img-alt

Require alt attribute on images for accessibility

Bad · Good

Default severity: warning
Presets: none
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": {
        "a11y/img-alt": "warn"
      }
    },
  },
});
vp run lint

Bad

The avatar image is missing its alt attribute.

<template>
  <img src="/avatar.png" />
</template>

Good

alt="User avatar" supplies a text alternative for the avatar.

<template>
  <img src="/avatar.png" alt="User avatar" />
</template>

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

Implementation · All rules

a11y/interactive-supports-focus

Require interactive role elements to be focusable

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": {
        "a11y/interactive-supports-focus": "warn"
      }
    },
  },
});
vp run lint

Bad

Giving a span the button role and a click handler does not make the element keyboard-focusable.

<template>
  <span role="button" @click="open">Open</span>
</template>

Good

The native button is focusable and retains the same open action.

<template>
  <button type="button" @click="open">Open</button>
</template>

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

Implementation · All rules

a11y/label-has-for

Require labels to have associated form controls

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": {
        "a11y/label-has-for": "warn"
      }
    },
  },
});
vp run lint

Bad

The separate label is neither associated through for nor wrapped around the input.

<template>
  <label>Email</label>
  <input id="email" />
</template>

Good

for="email" matches the input ID and explicitly associates the two elements.

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

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

Implementation · All rules

a11y/landmark-roles

Validate landmark role placement and uniqueness

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": {
        "a11y/landmark-roles": "warn"
      }
    },
  },
});
vp run lint

Bad

Two main elements declare duplicate main landmarks in the same template.

<template>
  <main>Dashboard</main>
  <main>Settings</main>
</template>

Good

The dashboard remains the main landmark; the settings area becomes a named navigation landmark.

<template>
  <main>Dashboard</main>
  <nav aria-label="Settings">...</nav>
</template>

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

Implementation · All rules

a11y/media-has-caption

Require media elements to have captions

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": {
        "a11y/media-has-caption": "warn"
      }
    },
  },
});
vp run lint

Bad

The video has playback controls but no caption track.

<template>
  <video src="/demo.mp4" controls />
</template>

Good

A track with kind="captions" supplies the English captions for the same video.

<template>
  <video src="/demo.mp4" controls>
    <track kind="captions" src="/demo.en.vtt" srclang="en" label="English" />
  </video>
</template>

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

Implementation · All rules