Vize

Vue rules

Every Vue rule has its purpose, configuration, Bad and Good examples on this page. Highlighted lines show the change; copied code keeps the complete source.

Rule Examples Purpose
vue/a11y-img-alt Bad · Good Require alt attribute on images for accessibility
vue/attribute-hyphenation Bad · Good Enforce attribute naming style on custom components
vue/attribute-order Bad · Good Enforce a consistent order of attributes
vue/component-definition-name-casing Bad · Good Enforce PascalCase or kebab-case for component definition names
vue/component-name-in-template-casing Bad · Good Enforce specific casing for component names in templates
vue/html-button-has-type Bad · Good Require an explicit valid type on button elements
vue/html-quotes Bad · Good Enforce quotes style of HTML attributes
vue/html-self-closing Bad · Good Enforce self-closing style
vue/max-template-complexity Bad · Good Limit a component's own template complexity (cyclomatic and cognitive)
vue/multi-word-component-names Bad · Good Require component names to be multi-word
vue/mustache-interpolation-spacing Bad · Good Enforce consistent spacing inside mustache interpolations
vue/no-array-index-key Bad · Good Disallow using the v-for index variable directly as the :key
vue/no-bare-strings-in-template Bad · Good Disallow raw human-readable text in the template that should be internationalized
vue/no-boolean-attr-value Bad · Good Disallow explicit values for boolean HTML attributes
vue/no-child-content Bad · Good Disallow child content when using v-html or v-text
vue/no-deprecated-filter Bad · Good Disallow deprecated Vue 2 filter syntax using the pipe operator
vue/no-deprecated-functional-template Bad · Good Disallow the functional attribute on the SFC <template>
vue/no-deprecated-html-element-is Bad · Good Disallow the is attribute on native HTML elements
vue/no-deprecated-inline-template Bad · Good Disallow the deprecated inline-template attribute
vue/no-deprecated-router-link-tag-prop Bad · Good Disallow the tag prop on <router-link>
vue/no-deprecated-scope-attribute Bad · Good Disallow the deprecated scope attribute on <template>
vue/no-deprecated-slot-attribute Bad · Good Disallow the deprecated slot attribute
vue/no-deprecated-slot-scope-attribute Bad · Good Disallow the deprecated slot-scope attribute
vue/no-deprecated-v-bind-sync Bad · Good Disallow the deprecated .sync modifier on v-bind
vue/no-deprecated-v-on-native-modifier Bad · Good Disallow the deprecated .native modifier on v-on
vue/no-deprecated-v-on-number-modifiers Bad · Good Disallow deprecated numeric keyCode modifiers on v-on
vue/no-dupe-v-else-if Bad · Good Disallow duplicate conditions in v-if / v-else-if chains
vue/no-duplicate-attributes Bad · Good Disallow duplicate attributes on the same element
vue/no-empty-component-block Bad · Good Disallow empty SFC blocks
vue/no-inline-style Bad · Good Discourage use of inline style attributes
vue/no-invalid-html-attribute Bad · Good Disallow invalid static values for HTML attributes
vue/no-lone-template Bad · Good Disallow unnecessary <template> elements
vue/no-multi-spaces Bad · Good Disallow multiple consecutive spaces
vue/no-multiple-objects-in-class Bad · Good Disallow multiple object literals inside a :class array binding
vue/no-multiple-template-root Bad · Good Disallow multiple root nodes in a template
vue/no-mutating-props Bad · Good Disallow mutating component props
vue/no-negated-v-if-condition Bad · Good Disallow a negated v-if condition when the chain has a v-else
vue/no-non-component-keep-alive-child Bad · Good Disallow plain element wrappers directly below <KeepAlive>
vue/no-preprocessor-lang Bad · Good Discourage CSS preprocessor usage in favor of modern CSS
vue/no-reserved-component-names Bad · Good Disallow the use of reserved names as component names
vue/no-root-v-if Bad · Good Disallow v-if on the single root element of a template
vue/no-script-non-standard-lang Bad · Good Discourage non-standard script lang values
vue/no-src-attribute Bad · Good Discourage src attribute on SFC blocks
vue/no-static-inline-styles Bad · Good Disallow static inline style attributes
vue/no-template-key Bad · Good Disallow key attribute on <template>
vue/no-template-lang Bad · Good Discourage lang attribute on template block
vue/no-template-shadow Bad · Good Disallow variable names that shadow variables in outer scope
vue/no-template-target-blank Bad · Good Disallow target="_blank" without rel="noopener noreferrer"
vue/no-textarea-mustache Bad · Good Disallow mustache interpolation in <textarea>
vue/no-undefined-refs Bad · Good Disallow undefined variable references in templates
vue/no-unsafe-url Bad · Good Warn about potentially unsafe URL bindings
vue/no-unsandboxed-iframe Bad · Good Require a sandbox attribute on iframe elements
vue/no-unused-components Bad · Good Disallow registering components that are not used inside templates
vue/no-unused-properties Bad · Good Disallow unused properties defined in defineProps
vue/no-unused-refs Bad · Good Report template refs (ref="x") never referenced in <script>
vue/no-unused-setup-bindings Bad · Good Disallow unread script setup bindings
vue/no-unused-vars Bad · Good Disallow unused variable definitions in v-for and v-slot directives
vue/no-use-v-else-with-v-for Bad · Good Disallow using v-else-if or v-else on the same element as v-for
vue/no-use-v-if-with-v-for Bad · Good Disallow using v-if on the same element as v-for
vue/no-useless-mustaches Bad · Good Disallow a mustache interpolation whose expression is a constant string literal
vue/no-useless-template-attributes Bad · Good Disallow useless attributes on <template> elements
vue/no-useless-v-bind Bad · Good Disallow a v-bind whose value is a plain string literal
vue/no-v-for-template-key-on-child Bad · Good Disallow key on the child of a <template v-for>
vue/no-v-html Bad · Good Warn against v-html to prevent XSS vulnerabilities
vue/no-v-text Bad · Good Disallow the v-text directive; prefer mustache interpolation
vue/no-v-text-v-html-on-component Bad · Good Disallow v-text / v-html on component elements
vue/permitted-contents Bad · Good Enforce HTML content model rules
vue/prefer-props-shorthand Bad · Good Recommend shorthand syntax for props (Vue 3.4+)
vue/prefer-true-attribute-shorthand Bad · Good Prefer the shorthand for a boolean attribute bound to true
vue/prop-name-casing Bad · Good Enforce a casing for declared prop names
vue/require-component-is Bad · Good Require v-bind:is on <component> elements
vue/require-component-registration Bad · Good Require explicit import or registration for components
vue/require-scoped-style Bad · Good Require scoped attribute on style tags
vue/require-toggle-inside-transition Bad · Good Require a toggle on the element wrapped by <transition>
vue/require-v-for-key Bad · Good Require v-bind:key with v-for directives
vue/scoped-event-names Bad · Good Recommend scoped event names using context:event format
vue/sfc-element-order Bad · Good Enforce consistent order of SFC top-level elements
vue/single-style-block Bad · Good Recommend having a single style block
vue/slot-name-casing Bad · Good Enforce kebab-case for named slots used via v-slot
vue/this-in-template Bad · Good Disallow this. in template expressions
vue/use-unique-element-ids Bad · Good Enforce unique element IDs using useId() instead of static literals
vue/use-v-on-exact Bad · Good Enforce .exact modifier on v-on when there are modifier-based handlers
vue/v-bind-style Bad · Good Enforce v-bind directive style
vue/v-on-event-hyphenation Bad · Good Enforce hyphenation of custom event names in v-on on components
vue/v-on-handler-style Bad · Good Enforce writing v-on handlers as a method reference or an inline function
vue/v-on-style Bad · Good Enforce v-on directive style
vue/v-slot-style Bad · Good Enforce v-slot directive style
vue/valid-attribute-name Bad · Good Require valid attribute names
vue/valid-template-root Bad · Good Enforce a valid <template> root for Vue 3 fragment semantics
vue/valid-v-bind Bad · Good Enforce valid v-bind directives
vue/valid-v-cloak Bad · Good Enforce valid v-cloak directives
vue/valid-v-else Bad · Good Enforce valid v-else directives
vue/valid-v-for Bad · Good Enforce valid v-for directives
vue/valid-v-html Bad · Good Enforce valid v-html directives
vue/valid-v-if Bad · Good Enforce valid v-if directives
vue/valid-v-memo Bad · Good Enforce valid v-memo directives
vue/valid-v-model Bad · Good Enforce valid v-model directives
vue/valid-v-on Bad · Good Enforce valid v-on directives
vue/valid-v-once Bad · Good Enforce valid v-once directives
vue/valid-v-show Bad · Good Enforce valid v-show directives
vue/valid-v-slot Bad · Good Enforce valid v-slot directives
vue/valid-v-text Bad · Good Enforce valid v-text directives
vue/warn-custom-block Bad · Good Warn about custom blocks in SFC files
vue/warn-custom-directive Bad · Good Warn about custom directives that need registration

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

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

Bad

Neither the static image nor the dynamically sourced image supplies an alt attribute.

<template>
<img src="/photo.jpg" />
<img :src="photo" />
</template>

Good

Informative images get descriptive alt text, decoration gets an empty alt, and the dynamic image binds its description.

<template>
<!-- Informative image -->
<img src="/photo.jpg" alt="Team photo from company retreat" />

<!-- Decorative image (empty alt) -->
<img src="/decoration.svg" alt="" />

<!-- Dynamic alt -->
<img :src="photo" :alt="photoDescription" />
</template>

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

Implementation · All rules

vue/attribute-hyphenation

Enforce attribute naming style on custom components

Bad · Good

Default severity: warning
Presets: happy-path, nuxt, ecosystem, opinionated
Automatic fix: Available for supported findings
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": {
        "vue/attribute-hyphenation": "warn"
      }
    },
  },
});
vp run lint

Bad

The component attribute uses the camelCase spelling firstName.

<template>
<UserCard firstName="Ada" />
</template>

Good

The first-name spelling follows the configured hyphenated component-attribute convention.

<template>
<UserCard first-name="Ada" />
</template>

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

Implementation · All rules

vue/attribute-order

Enforce a consistent order of 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": {
        "vue/attribute-order": "warn"
      }
    },
  },
});
vp run lint

Bad

The event handler appears before the structural v-if directive and ordinary id attribute.

<template>
  <div @click="onClick" v-if="show" id="main"></div>
</template>

Good

v-if comes first, followed by id and then the event handler, following the rule ordering.

<template>
  <div v-if="show" id="main" @click="onClick"></div>
</template>

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

Implementation · All rules

vue/component-definition-name-casing

Enforce PascalCase or kebab-case for component definition names

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.

The component filename is checked. PascalCase and kebab-case are accepted; mixed casing is reported.

Configuration (Vite+)

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

export default defineConfig({
  lint: {
    vize: {
      "preset": "incremental",
      "rules": {
        "vue/component-definition-name-casing": "warn"
      }
    },
  },
});
vp run lint

Bad

The filename myComponent.vue mixes a lowercase initial with an internal uppercase letter instead of using PascalCase or kebab-case.

myComponent.vue

<template><p>Content</p></template>

Good

Renaming the file to MyComponent.vue uses PascalCase; its template content is unchanged.

MyComponent.vue

<template><p>Content</p></template>

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

Implementation · All rules

vue/component-name-in-template-casing

Enforce specific casing for component names in templates

Bad · Good

Default severity: warning
Presets: nuxt, opinionated
Automatic fix: Available for supported findings
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": {
        "vue/component-name-in-template-casing": "warn"
      }
    },
  },
});
vp run lint

Bad

The component is written in kebab-case and camelCase under the PascalCase convention.

<script setup>
import MyComponent from "./MyComponent.vue";
</script>
<template>
  <my-component />
  <myComponent />
</template>

Good

MyComponent uses PascalCase; native slot syntax remains lowercase.

<script setup>
import MyComponent from "./MyComponent.vue";
</script>
<template>
  <MyComponent />
  <RouterView />
  <slot />
</template>

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

Implementation · All rules

vue/html-button-has-type

Require an explicit valid type on button elements

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": {
        "vue/html-button-has-type": "warn"
      }
    },
  },
});
vp run lint

Bad

One button omits type and another supplies the unsupported foo type.

<template>
<button>Click</button>
<button type="foo">Click</button>
</template>

Good

Buttons specify button, submit, or reset; a bound type is treated as dynamic.

<template>
<button type="button">Click</button>
<button type="submit">Save</button>
<button type="reset">Reset</button>
<button :type="dynamicType">Click</button>
</template>

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

Implementation · All rules

vue/html-quotes

Enforce quotes style of HTML attributes

Bad · Good

Default severity: warning
Presets: happy-path, nuxt, ecosystem, opinionated
Automatic fix: Available for supported findings
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": {
        "vue/html-quotes": "warn"
      }
    },
  },
});
vp run lint

Bad

The attributes use single quotes or no quotes instead of the double-quote convention.

<template>
  <div class='foo'></div>
  <div class=foo></div>
  <div v-if='ready'></div>
</template>

Good

Both ordinary attributes and directive expressions use double quotes.

<template>
  <div class="foo"></div>
  <div v-if="ready"></div>
</template>

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

Implementation · All rules

vue/html-self-closing

Enforce self-closing style

Bad · Good

Default severity: warning
Presets: nuxt, opinionated
Automatic fix: Available for supported findings
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": {
        "vue/html-self-closing": "warn"
      }
    },
  },
});
vp run lint

Bad

The empty component uses a closing pair, while void img and br elements omit the configured self-closing spelling.

<template>
  <MyComponent></MyComponent>
  <img>
  <br>
</template>

Good

The component and void elements use self-closing syntax; a div with content retains its closing tag.

<template>
  <MyComponent />
  <div></div>
  <div />
  <img />
  <br />
  <div>content</div>
</template>

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

Implementation · All rules

vue/max-template-complexity

Limit a component's own template complexity (cyclomatic and cognitive)

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.

Bad has cyclomatic complexity 13 and cognitive complexity 25 (limits: 11 and 16). Each component is measured separately; only inline HTML templates are supported.

See complexity scoring and component boundaries for the contributions behind the example's two scores.

Configuration (Vite+)

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

export default defineConfig({
  lint: {
    vize: {
      "preset": "incremental",
      "rules": {
        "vue/max-template-complexity": "warn"
      }
    },
  },
});
vp run lint

Bad

The parent-authored branches, loop, slot content, and expression decisions produce scores of 13 and 25, above the default limits 11 and 16.

<script setup lang="ts">
defineProps<{ rows: Row[] }>();
</script>
<template>
  <section>
    <h1>{{ user ? user.name : 'Guest' }}</h1>
    <DataTable :rows="rows">
      <template #cell="{ row, column }">
        <span v-if="column.key === 'status'" :class="row.active ? 'on' : 'off'">{{ row.status ?? 'unknown' }}</span>
        <a v-else-if="column.key === 'link' && row.url" :href="row.url">{{ row.label }}</a>
        <template v-else>
          <em v-for="tag in row.tags" :key="tag">
            <b v-if="tag.pinned || tag.starred">{{ tag.hot ? '!' : '' }}</b>
          </em>
        </template>
      </template>
    </DataTable>
    <p v-if="!rows.length && !loading">No data</p>
  </section>
</template>

Good

The parent template delegates rendering to RowList and keeps one v-if; its own scores are 2 and 1.

<template>
  <RowList v-if="ready" :rows="rows" />
</template>

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

Implementation · All rules

vue/multi-word-component-names

Require component names to be multi-word

Bad · Good

Default severity: error
Presets: essential, 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.

The filename is the finding. Rename the same component; changing a child tag does not fix it.

Configuration (Vite+)

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

export default defineConfig({
  lint: {
    vize: {
      "preset": "incremental",
      "rules": {
        "vue/multi-word-component-names": "error"
      }
    },
  },
});
vp run lint

Bad

Item.vue gives the component a single-word name.

Item.vue

<template><p>Item</p></template>

Good

TodoItem.vue gives the same template a multi-word component name.

TodoItem.vue

<template><p>Item</p></template>

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

Implementation · All rules

vue/mustache-interpolation-spacing

Enforce consistent spacing inside mustache interpolations

Bad · Good

Default severity: warning
Presets: happy-path, nuxt, ecosystem, opinionated
Automatic fix: Available for supported findings
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": {
        "vue/mustache-interpolation-spacing": "warn"
      }
    },
  },
});
vp run lint

Bad

The text interpolation is missing a space at one or both delimiter boundaries.

<template>
  <div>{{text}}</div>
  <div>{{ text}}</div>
  <div>{{text }}</div>
</template>

Good

Spaces separate the expression from both opening and closing mustache delimiters.

<template>
  <div>{{ text }}</div>
  <div>{{ foo.bar }}</div>
  <div>{{ foo + bar }}</div>
</template>

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

Implementation · All rules

vue/no-array-index-key

Disallow using the v-for index variable directly as the :key

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": {
        "vue/no-array-index-key": "warn"
      }
    },
  },
});
vp run lint

Bad

The list key is its current index, so item identity changes when the list is reordered.

<template>
<li v-for="(item, index) in items" :key="index">{{ item.name }}</li>
</template>

Good

The key comes from item.id, preserving the identity of each item across position changes.

<template>
<li v-for="item in items" :key="item.id">{{ item.name }}</li>
</template>

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

Implementation · All rules

vue/no-bare-strings-in-template

Disallow raw human-readable text in the template that should be internationalized

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": {
        "vue/no-bare-strings-in-template": "warn"
      }
    },
  },
});
vp run lint

Bad

Visible text and naming attributes embed untranslated strings directly in the template.

<template>
<div>hello</div>
<img alt="a cat" />
<input placeholder="Search" />
<button title="Close">x</button>
</template>

Good

Translatable content calls $t; the punctuation and numeric-only examples are allowed exceptions.

<template>
<div>{{ $t('hello') }}</div>
<img :alt="$t('cat')" />
<div>-</div>
<div>123</div>
<button :title="$t('close')">{{ $t('x') }}</button>
</template>

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

Implementation · All rules

vue/no-boolean-attr-value

Disallow explicit values for boolean HTML attributes

Bad · Good

Default severity: warning
Presets: nuxt, opinionated
Automatic fix: Available for supported findings
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": {
        "vue/no-boolean-attr-value": "warn"
      }
    },
  },
});
vp run lint

Bad

The boolean disabled and checked attributes redundantly contain string values.

<template>
  <input disabled="disabled" />
  <input checked="checked" />
  <button disabled="true">Save</button>
</template>

Good

The presence of each boolean attribute expresses the same enabled state without a value.

<template>
  <input disabled />
  <input checked />
  <button disabled>Save</button>
</template>

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

Implementation · All rules

vue/no-child-content

Disallow child content when using v-html or v-text

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": {
        "vue/no-child-content": "error"
      }
    },
  },
});
vp run lint

Bad

v-text replaces the paragraph content, so the authored fallback text cannot survive that directive.

<template>
  <p v-text="message">Fallback text</p>
</template>

Good

Removing the child text leaves v-text as the single source of paragraph content.

<template>
  <p v-text="message" />
</template>

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

Implementation · All rules

vue/no-deprecated-filter

Disallow deprecated Vue 2 filter syntax using the pipe operator

Bad · Good

Default severity: error
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": {
        "vue/no-deprecated-filter": "error"
      }
    },
  },
});
vp run lint

Bad

The pipe uses the removed Vue filter syntax to apply capitalize.

<template>
{{ message | capitalize }}
</template>

Good

Calling capitalize(message) applies the transformation as an ordinary expression.

<template>
{{ capitalize(message) }}
</template>

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

Implementation · All rules

vue/no-deprecated-functional-template

Disallow the functional attribute on the SFC <template>

Bad · Good

Default severity: error
Presets: ecosystem, essential, happy-path, 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": {
        "vue/no-deprecated-functional-template": "error"
      }
    },
  },
});
vp run lint

Bad

The SFC template has the removed functional attribute and reads the old props context.

<template functional>
<div>{{ props.msg }}</div>
</template>

Good

The ordinary template omits functional and reads the component binding msg directly.

<template>
<div>{{ msg }}</div>
</template>

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

Implementation · All rules

vue/no-deprecated-html-element-is

Disallow the is attribute on native HTML elements

Bad · Good

Default severity: error
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": {
        "vue/no-deprecated-html-element-is": "error"
      }
    },
  },
});
vp run lint

Bad

A native div uses the old unprefixed is attribute to request a Vue component.

<template>
<div is="MyComponent" />
</template>

Good

A dynamic component uses :is; the native-element spelling explicitly uses the vue: prefix.

<template>
<component :is="MyComponent" />
<div is="vue:MyComponent" />
</template>

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

Implementation · All rules

vue/no-deprecated-inline-template

Disallow the deprecated inline-template attribute

Bad · Good

Default severity: error
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": {
        "vue/no-deprecated-inline-template": "error"
      }
    },
  },
});
vp run lint

Bad

Card uses the deprecated inline-template attribute for its supplied content.

<template>
<Card inline-template><p>Details</p></Card>
</template>

Good

The same content is passed normally without the inline-template attribute.

<template>
<Card><p>Details</p></Card>
</template>

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

Implementation · All rules

Disallow the tag prop on <router-link>

Bad · Good

Default severity: error
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": {
        "vue/no-deprecated-router-link-tag-prop": "error"
      }
    },
  },
});
vp run lint

Bad

RouterLink uses the removed tag prop to request a button element.

<template>
<router-link to="/home" tag="button">Home</router-link>
</template>

Good

The slot provides navigate to an explicitly authored button.

<template>
<router-link to="/home" v-slot="{ navigate }">
<button @click="navigate">Home</button>
</router-link>
</template>

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

Implementation · All rules

vue/no-deprecated-scope-attribute

Disallow the deprecated scope attribute on <template>

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": {
        "vue/no-deprecated-scope-attribute": "error"
      }
    },
  },
});
vp run lint

Bad

The slot template declares props through the deprecated scope attribute.

<template>
<Card><template scope="props">{{ props.name }}</template></Card>
</template>

Good

The default-slot directive declares the same props binding through current slot syntax.

<template>
<Card><template #default="props">{{ props.name }}</template></Card>
</template>

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

Implementation · All rules

vue/no-deprecated-slot-attribute

Disallow the deprecated slot attribute

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": {
        "vue/no-deprecated-slot-attribute": "error"
      }
    },
  },
});
vp run lint

Bad

The header slot is selected through the old slot attribute.

<template>
<Foo>
<template slot="header"><h1>Title</h1></template>
<div :slot="name">Title</div>
</Foo>
</template>

Good

v-slot:header explicitly selects the header slot with the current directive.

<template>
<Foo>
<template v-slot:header><h1>Title</h1></template>
</Foo>
</template>

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

Implementation · All rules

vue/no-deprecated-slot-scope-attribute

Disallow the deprecated slot-scope attribute

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": {
        "vue/no-deprecated-slot-scope-attribute": "error"
      }
    },
  },
});
vp run lint

Bad

The template receives slot props through the deprecated slot-scope attribute.

<template>
<Card><template slot-scope="props">{{ props.name }}</template></Card>
</template>

Good

The #default directive receives those props without slot-scope.

<template>
<Card><template #default="props">{{ props.name }}</template></Card>
</template>

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

Implementation · All rules

vue/no-deprecated-v-bind-sync

Disallow the deprecated .sync modifier on v-bind

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": {
        "vue/no-deprecated-v-bind-sync": "error"
      }
    },
  },
});
vp run lint

Bad

The bindings use the removed .sync modifier, including its combination with .camel.

<template>
<MyComponent :title.sync="title" />
<MyComponent v-bind:title.sync="title" />
<MyComponent :title.sync.camel="title" />
</template>

Good

Use an ordinary one-way title binding or v-model:title when an update channel is required.

<template>
<MyComponent :title="title" />
<MyComponent v-model:title="title" />
</template>

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

Implementation · All rules

vue/no-deprecated-v-on-native-modifier

Disallow the deprecated .native modifier on v-on

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": {
        "vue/no-deprecated-v-on-native-modifier": "error"
      }
    },
  },
});
vp run lint

Bad

The component handlers use the removed .native event modifier.

<template>
<MyComponent @click.native="handler" />
<MyComponent v-on:click.native="handler" />
<MyComponent @click.native.stop="handler" />
</template>

Good

The handlers omit .native and preserve other event modifiers such as .stop.

<template>
<MyComponent @click="handler" />
<MyComponent @click.stop="handler" />
</template>

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

Implementation · All rules

vue/no-deprecated-v-on-number-modifiers

Disallow deprecated numeric keyCode modifiers on v-on

Bad · Good

Default severity: error
Presets: ecosystem, essential, happy-path, 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": {
        "vue/no-deprecated-v-on-number-modifiers": "error"
      }
    },
  },
});
vp run lint

Bad

The keyboard handlers identify keys by the removed numeric codes 13 and 27.

<template>
<input @keyup.13="submit" />
<input v-on:keyup.27="cancel" />
<input @keyup.13.stop="submit" />
</template>

Good

The handlers use the named enter and esc key modifiers.

<template>
<input @keyup.enter="submit" />
<input @keyup.esc="cancel" />
</template>

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

Implementation · All rules

vue/no-dupe-v-else-if

Disallow duplicate conditions in v-if / v-else-if chains

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": {
        "vue/no-dupe-v-else-if": "error"
      }
    },
  },
});
vp run lint

Bad

The else-if repeats the ready condition already tested by the first branch, making that later branch unreachable.

<template>
  <p v-if="status === 'ready'">Ready</p>
  <p v-else-if="status === 'ready'">Still ready</p>
</template>

Good

The second branch tests loading, a distinct state that can reach the else-if.

<template>
  <p v-if="status === 'ready'">Ready</p>
  <p v-else-if="status === 'loading'">Loading</p>
</template>

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

Implementation · All rules

vue/no-duplicate-attributes

Disallow duplicate attributes on the same element

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": {
        "vue/no-duplicate-attributes": "error"
      }
    },
  },
});
vp run lint

Bad

The same button declares class twice instead of one combined class value.

<template>
  <button class="primary" class="large">Save</button>
</template>

Good

Both class tokens appear in a single class attribute.

<template>
  <button class="primary large">Save</button>
</template>

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

Implementation · All rules

vue/no-empty-component-block

Disallow empty SFC blocks

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": {
        "vue/no-empty-component-block": "warn"
      }
    },
  },
});
vp run lint

Bad

The template, script, and style blocks contain no meaningful content.

<template></template>

<script></script>

<style>
</style>

Good

Each retained block contains actual markup, script declarations, or style declarations.

<template>
<div>Hello</div>
</template>

<script setup>
const message = "Hello";
</script>

<style scoped>
.button { color: red; }
</style>

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

Implementation · All rules

vue/no-inline-style

Discourage use of 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": {
        "vue/no-inline-style": "warn"
      }
    },
  },
});
vp run lint

Bad

The static style attribute embeds the color declaration in the element.

<template>
  <div style="color: red">Text</div>
</template>

Good

Classes express the fixed color; the ratio-dependent width remains a dynamic style binding, outside the static-attribute check.

<template>
  <div class="text-red">Text</div>
  <span :class="{ 'text-red': isRed }">Text</span>
  <div :style="{ width: `${ratio}%` }">Text</div>
</template>

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

Implementation · All rules

vue/no-invalid-html-attribute

Disallow invalid static values for 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": {
        "vue/no-invalid-html-attribute": "warn"
      }
    },
  },
});
vp run lint

Bad

The anchor uses stylesheet as a rel value, although that value belongs to stylesheet link elements.

<template>
<a href="/guide" rel="stylesheet">Guide</a>
</template>

Good

The anchor uses help, a rel value appropriate for a linked help resource.

<template>
<a href="/guide" rel="help">Guide</a>
</template>

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

Implementation · All rules

vue/no-lone-template

Disallow unnecessary <template> 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": {
        "vue/no-lone-template": "warn"
      }
    },
  },
});
vp run lint

Bad

The inner template has no directive or slot role that gives it a structural purpose.

<template>
<div><template><p>Details</p></template></div>
</template>

Good

Removing the unnecessary wrapper leaves the paragraph directly inside div.

<template>
<div><p>Details</p></div>
</template>

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

Implementation · All rules

vue/no-multi-spaces

Disallow multiple consecutive spaces

Bad · Good

Default severity: warning
Presets: happy-path, nuxt, ecosystem, opinionated
Automatic fix: Available for supported findings
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": {
        "vue/no-multi-spaces": "warn"
      }
    },
  },
});
vp run lint

Bad

Two spaces separate attributes or the element name and the first attribute.

<template>
  <div  class="panel"></div>
  <div class="panel"  id="main"></div>
</template>

Good

Single spaces separate the same attributes.

<template>
  <div class="panel"></div>
  <div class="panel" id="main"></div>
</template>

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

Implementation · All rules

vue/no-multiple-objects-in-class

Disallow multiple object literals inside a :class array binding

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": {
        "vue/no-multiple-objects-in-class": "warn"
      }
    },
  },
});
vp run lint

Bad

A class array contains two top-level object literals that can be merged.

<template>
<div :class="[{ a }, { b }]"></div>
<div :class="[{ active: isActive }, { error: hasError }]"></div>
</template>

Good

One object contains the class conditions; arrays with one object and a string or with non-literal entries remain allowed.

<template>
<div :class="{ a, b }"></div>
<div :class="[{ active: isActive }, 'static']"></div>
<div :class="[foo, bar]"></div>
</template>

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

Implementation · All rules

vue/no-multiple-template-root

Disallow multiple root nodes in a template

Bad · Good

Default severity: error
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.

Enable only for a single-root contract. Vue 3 normally supports fragments.

Configuration (Vite+)

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

export default defineConfig({
  lint: {
    vize: {
      "preset": "incremental",
      "rules": {
        "vue/no-multiple-template-root": "error"
      }
    },
  },
});
vp run lint

Bad

The opt-in single-root convention sees two sibling paragraphs at the template root.

<template>
<p>First</p>
<p>Second</p>
</template>

Good

A section wraps the paragraphs into one root; enable this convention only when a single-root contract is intended.

<template>
<section><p>First</p><p>Second</p></section>
</template>

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

Implementation · All rules

vue/no-mutating-props

Disallow mutating component props

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: See typed options and defaults.

Configuration (Vite+)

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

export default defineConfig({
  lint: {
    vize: {
      "preset": "incremental",
      "rules": {
        "vue/no-mutating-props": "error"
      }
    },
  },
});
vp run lint

Bad

Incrementing props.count writes directly to a value supplied by the parent.

<script setup lang="ts">
const props = defineProps<{ count: number }>();

props.count++;
</script>

Good

The component emits update:count with the next value, leaving the parent responsible for updating the prop.

<script setup lang="ts">
const props = defineProps<{ count: number }>();
const emit = defineEmits<{ "update:count": [value: number] }>();

function increment() {
  emit("update:count", props.count + 1);
}
</script>

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

Implementation · All rules

vue/no-negated-v-if-condition

Disallow a negated v-if condition when the chain has a v-else

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": {
        "vue/no-negated-v-if-condition": "warn"
      }
    },
  },
});
vp run lint

Bad

The paired v-if and v-else branches begin with a negated condition.

<template>
<div v-if="!ok">A</div>
<div v-else>B</div>
</template>

Good

A positive ok condition comes first; when inverting a condition, place the original opposite branch first. A lone negated v-if and !== comparisons remain allowed.

<template>
<div v-if="ok">B</div>
<div v-else>A</div>

<div v-if="!ok">A</div>

<div v-if="a !== b">A</div>
<div v-else>B</div>
</template>

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

Implementation · All rules

vue/no-non-component-keep-alive-child

Disallow plain element wrappers directly below <KeepAlive>

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": {
        "vue/no-non-component-keep-alive-child": "warn"
      }
    },
  },
});
vp run lint

Bad

KeepAlive conditionally wraps a native div rather than directly caching UserCard.

<template>
  <KeepAlive>
    <div v-if="ready">
      <UserCard />
    </div>
  </KeepAlive>
</template>

Good

The first example makes UserCard the conditional child. The v-show wrapper illustrates a shape outside this conditional-child check, not a promise that the native wrapper is cached.

<template>
  <KeepAlive>
    <UserCard v-if="ready" />
  </KeepAlive>
  <KeepAlive>
    <div v-show="opened">
      <UserCard />
    </div>
  </KeepAlive>
</template>

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

Implementation · All rules

vue/no-preprocessor-lang

Discourage CSS preprocessor usage in favor of modern CSS

Bad · Good

Default severity: warning
Presets: nuxt, opinionated
Automatic fix: Not implemented for SFC lint
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.

Current support: no-sfc-finding

This catalog entry does not currently emit its rule-specific finding through SFC lint. The Bad/Good pair describes the intended convention, not an executable finding. Enabling the ID does not supply the missing SFC check.

Configured ID (currently no SFC finding)

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

export default defineConfig({
  lint: {
    vize: {
      "preset": "incremental",
      "rules": {
        "vue/no-preprocessor-lang": "warn"
      }
    },
  },
});
vp run lint

Bad

The style block selects SCSS with lang. This describes the intended no-preprocessor convention; the current SFC path does not emit this rule.

<template><p>Notice</p></template>
<style lang="scss">
.notice { color: red; }
</style>

Good

The same CSS declarations omit the preprocessor lang. This is the convention repair, not an executable Bad/Good diagnostic difference today.

<template><p>Notice</p></template>
<style>
.notice { color: red; }
</style>

Good illustrates the intended convention; the current SFC path emits neither side's rule-specific finding.

Implementation · All rules

vue/no-reserved-component-names

Disallow the use of reserved names as component names

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": {
        "vue/no-reserved-component-names": "error"
      }
    },
  },
});
vp run lint

Bad

The component name button conflicts with a native HTML element name.

<script>
export default {
  name: "button",
};
</script>

Good

AppButton is an application component name and does not reuse the native button name.

<script setup lang="ts">
defineOptions({ name: "AppButton" });
</script>

<template>
  <Transition>
    <AppButton />
  </Transition>
</template>

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

Implementation · All rules

vue/no-root-v-if

Disallow v-if on the single root element of a template

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": {
        "vue/no-root-v-if": "warn"
      }
    },
  },
});
vp run lint

Bad

The component root itself appears and disappears under v-if.

<template>
<div v-if="show">content</div>
</template>

Good

A stable outer div remains the root while the nested paragraph carries the visibility condition.

<template>
<div>
<p v-if="show">content</p>
</div>
</template>

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

Implementation · All rules

vue/no-script-non-standard-lang

Discourage non-standard script lang values

Bad · Good

Default severity: warning
Presets: nuxt, opinionated
Automatic fix: Not implemented for SFC lint
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.

Current support: no-sfc-finding

This catalog entry does not currently emit its rule-specific finding through SFC lint. The Bad/Good pair describes the intended convention, not an executable finding. Enabling the ID does not supply the missing SFC check.

Configured ID (currently no SFC finding)

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

export default defineConfig({
  lint: {
    vize: {
      "preset": "incremental",
      "rules": {
        "vue/no-script-non-standard-lang": "warn"
      }
    },
  },
});
vp run lint

Bad

The script uses CoffeeScript syntax under lang=coffee. The current SFC path does not emit this catalog rule for that language.

<script lang="coffee">
count = 0
</script>
<template><p>Notice</p></template>

Good

The script uses an ordinary TypeScript declaration with lang=ts, illustrating the intended language convention.

<script lang="ts">
const count = 0;
</script>
<template><p>Notice</p></template>

Good illustrates the intended convention; the current SFC path emits neither side's rule-specific finding.

Implementation · All rules

vue/no-src-attribute

Discourage src attribute on SFC blocks

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": {
        "vue/no-src-attribute": "warn"
      }
    },
  },
});
vp run lint

Bad

The SFC blocks delegate their template, script, and style content to src files.

<template src="./template.html"></template>
<script src="./script.ts"></script>
<style src="./style.css"></style>

Good

Each SFC block contains its own content without an external src attribute.

<template>
  <p>Hello</p>
</template>

<script setup lang="ts">
const label = "Hello";
</script>

<style scoped>
p {
  color: red;
}
</style>

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

Implementation · All rules

vue/no-static-inline-styles

Disallow static inline style attributes

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": {
        "vue/no-static-inline-styles": "warn"
      }
    },
  },
});
vp run lint

Bad

The paragraph carries the constant color declaration in its style attribute.

<template>
<p style="color: red">Notice</p>
</template>

Good

A notice class and scoped stylesheet hold the constant color outside the template attribute.

<template><p class="notice">Notice</p></template>
<style scoped>.notice { color: red; }</style>

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

Implementation · All rules

vue/no-template-key

Disallow key attribute on <template>

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": {
        "vue/no-template-key": "error"
      }
    },
  },
});
vp run lint

Bad

A non-loop template wrapper has a key even though it is not the keyed iteration boundary.

<template>
<template :key="section"><div>Details</div></template>
</template>

Good

The key belongs to a template v-for iteration, where it identifies each repeated fragment.

<template>
<template v-for="item in items" :key="item.id"><div>{{ item.name }}</div></template>
</template>

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

Implementation · All rules

vue/no-template-lang

Discourage lang attribute on template block

Bad · Good

Default severity: warning
Presets: nuxt, opinionated
Automatic fix: Not implemented for SFC lint
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.

Current support: no-sfc-finding

This catalog entry does not currently emit its rule-specific finding through SFC lint. The Bad/Good pair describes the intended convention, not an executable finding. Enabling the ID does not supply the missing SFC check.

Configured ID (currently no SFC finding)

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

export default defineConfig({
  lint: {
    vize: {
      "preset": "incremental",
      "rules": {
        "vue/no-template-lang": "warn"
      }
    },
  },
});
vp run lint

Bad

The template selects Pug through lang. This is an intended HTML-only convention; the current SFC path does not diagnose this catalog ID.

<template lang="pug">
p Notice
</template>

Good

An ordinary HTML template omits lang and uses the paragraph directly. This illustrates the convention without claiming a current SFC finding.

<template>
<p>Notice</p>
</template>

Good illustrates the intended convention; the current SFC path emits neither side's rule-specific finding.

Implementation · All rules

vue/no-template-shadow

Disallow variable names that shadow variables in outer scope

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.

The current check compares nested v-for bindings. It does not report a single v-for binding merely because it shares a script binding's name.

Configuration (Vite+)

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

export default defineConfig({
  lint: {
    vize: {
      "preset": "incremental",
      "rules": {
        "vue/no-template-shadow": "warn"
      }
    },
  },
});
vp run lint

Bad

The inner v-for declares item again and hides the outer item binding inside the nested loop.

<template>
<div v-for="item in items" :key="item.id"><span v-for="item in item.children" :key="item.id">{{ item.name }}</span></div>
</template>

Good

The inner loop declares child, leaving item available for the outer row and child for the nested row.

<template>
<div v-for="item in items" :key="item.id"><span v-for="child in item.children" :key="child.id">{{ child.name }}</span></div>
</template>

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

Implementation · All rules

vue/no-template-target-blank

Disallow target="_blank" without rel="noopener noreferrer"

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": {
        "vue/no-template-target-blank": "warn"
      }
    },
  },
});
vp run lint

Bad

The external link opens a new browsing context without the expected rel protection.

<template>
<a href="https://example.com" target="_blank">x</a>
</template>

Good

The same link includes noopener noreferrer alongside target=_blank.

<template>
<a href="https://example.com" target="_blank" rel="noopener noreferrer">x</a>
</template>

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

Implementation · All rules

vue/no-textarea-mustache

Disallow mustache interpolation in <textarea>

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": {
        "vue/no-textarea-mustache": "error"
      }
    },
  },
});
vp run lint

Bad

The textarea places message in child interpolation instead of binding its value.

<template>
  <textarea>{{ message }}</textarea>
</template>

Good

v-model binds the editable textarea value to message.

<template>
  <textarea v-model="message"></textarea>
</template>

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

Implementation · All rules

vue/no-undefined-refs

Disallow undefined variable references in templates

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": {
        "vue/no-undefined-refs": "warn"
      }
    },
  },
});
vp run lint

Bad

The template reads missing, although the script declares only message.

<script setup>const message = "Hello";</script>
<template>{{ missing }}</template>

Good

The interpolation reads the existing message binding.

<script setup>const message = "Hello";</script>
<template>{{ message }}</template>

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

Implementation · All rules

vue/no-unsafe-url

Warn about potentially unsafe URL bindings

Bad · Good

Default severity: warning
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": {
        "vue/no-unsafe-url": "warn"
      }
    },
  },
});
vp run lint

Bad

The anchor destination begins with the executable javascript: scheme.

<template>
<a href="javascript:alert(1)">Continue</a>
</template>

Good

The anchor uses the ordinary local /next navigation destination.

<template>
<a href="/next">Continue</a>
</template>

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

Implementation · All rules

vue/no-unsandboxed-iframe

Require a sandbox attribute on iframe 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": {
        "vue/no-unsandboxed-iframe": "warn"
      }
    },
  },
});
vp run lint

Bad

The embedded frame has no sandbox attribute limiting its capabilities.

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

Good

sandbox applies restrictions; allow-scripts explicitly opts into that one capability when needed.

<template>
<iframe src="/embed" sandbox></iframe>
<iframe src="/embed" sandbox="allow-scripts"></iframe>
</template>

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

Implementation · All rules

vue/no-unused-components

Disallow registering components that are not used inside templates

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": {
        "vue/no-unused-components": "warn"
      }
    },
  },
});
vp run lint

Bad

UserAvatar is imported as a component but the template never renders it.

<script setup lang="ts">
import UserAvatar from "./UserAvatar.vue";
</script>

<template>
  <p>{{ user.name }}</p>
</template>

Good

The template renders the imported UserAvatar and passes the user binding.

<script setup lang="ts">
import UserAvatar from "./UserAvatar.vue";
</script>

<template>
  <UserAvatar :user="user" />
</template>

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

Implementation · All rules

vue/no-unused-properties

Disallow unused properties defined in defineProps

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": {
        "vue/no-unused-properties": "warn"
      }
    },
  },
});
vp run lint

Bad

The component declares description as a prop but renders only title.

<script setup lang="ts">
defineProps<{ title: string; description: string }>();
</script>

<template>
  <h1>{{ title }}</h1>
</template>

Good

Both declared props are referenced by the template.

<script setup lang="ts">
defineProps<{ title: string; description: string }>();
</script>

<template>
  <h1>{{ title }}</h1>
  <p>{{ description }}</p>
</template>

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

Implementation · All rules

vue/no-unused-refs

Report template refs (ref="x") never referenced in <script>

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": {
        "vue/no-unused-refs": "warn"
      }
    },
  },
});
vp run lint

Bad

The template declares the unused ref name with no corresponding script reference binding.

<template><input ref="unused" /></template>
<script setup>
const x = 1
</script>

Good

The inputEl template ref has a same-named ref binding in script setup.

<template><input ref="inputEl" /></template>
<script setup>
import { ref } from 'vue'
const inputEl = ref(null)
</script>

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

Implementation · All rules

vue/no-unused-setup-bindings

Disallow unread script setup bindings

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": {
        "vue/no-unused-setup-bindings": "warn"
      }
    },
  },
});
vp run lint

Bad

The script setup message binding is never read by the template.

<script setup>const message = "Hello";</script>
<template><p>Welcome</p></template>

Good

The paragraph interpolates message, using the declared binding.

<script setup>const message = "Hello";</script>
<template><p>{{ message }}</p></template>

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

Implementation · All rules

vue/no-unused-vars

Disallow unused variable definitions in v-for and v-slot directives

Bad · Good

Default severity: warning
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": {
        "vue/no-unused-vars": "warn"
      }
    },
  },
});
vp run lint

Bad

The loop declares an unused index and the slot declares foo without referencing it.

<template>
  <li v-for="(item, index) in items" :key="item.id">{{ item.name }}</li>
  <template v-slot="{ foo }">
    <span>Hello</span>
  </template>
</template>

Good

The examples consume index or mark it intentionally unused as _index, and the slot renders data. Index keys are only a usage example here, not a recommendation for stable item identity.

<template>
  <li v-for="(item, index) in items" :key="index">{{ item.name }}</li>
  <li v-for="(item, _index) in items" :key="item.id">{{ item.name }}</li>
  <template v-slot="{ data }">
    <span>{{ data }}</span>
  </template>
</template>

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

Implementation · All rules

vue/no-use-v-else-with-v-for

Disallow using v-else-if or v-else on the same element as v-for

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": {
        "vue/no-use-v-else-with-v-for": "warn"
      }
    },
  },
});
vp run lint

Bad

The else branch and v-for iteration are attached to the same paragraph.

<template>
<p v-if="ready">Ready</p>
<p v-else v-for="item in items" :key="item.id">{{ item.name }}</p>
</template>

Good

A separate template owns v-else, and its child paragraph owns v-for.

<template>
<p v-if="ready">Ready</p>
<template v-else><p v-for="item in items" :key="item.id">{{ item.name }}</p></template>
</template>

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

Implementation · All rules

vue/no-use-v-if-with-v-for

Disallow using v-if on the same element as v-for

Bad · Good

Default severity: warning
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": {
        "vue/no-use-v-if-with-v-for": "warn"
      }
    },
  },
});
vp run lint

Bad

The same list element combines v-if and v-for and tests visibility through the loop binding.

<template>
  <li v-for="item in items" v-if="item.visible" :key="item.id">
    {{ item.name }}
  </li>
</template>

Good

A computed collection filters the visible items before the template iterates over them.

<script setup lang="ts">
const visibleItems = computed(() => items.filter((item) => item.visible));
</script>

<template>
  <li v-for="item in visibleItems" :key="item.id">
    {{ item.name }}
  </li>
</template>

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

Implementation · All rules

vue/no-useless-mustaches

Disallow a mustache interpolation whose expression is a constant string literal

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": {
        "vue/no-useless-mustaches": "warn"
      }
    },
  },
});
vp run lint

Bad

The interpolation contains only a constant string and does not need expression evaluation.

<template>
<div>{{ 'x' }}</div>
<div>{{ "x" }}</div>
<div>{{ `x` }}</div>
</template>

Good

Literal text is written directly; variable expressions, interpolated template strings, and intentional separator whitespace remain interpolation cases.

<template>
<div>x</div>
<div>{{ x }}</div>
<div>{{ `pre-${x}` }}</div>
<span>A</span> {{ " " }} <span>B</span>
</template>

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

Implementation · All rules

vue/no-useless-template-attributes

Disallow useless attributes on <template> elements

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": {
        "vue/no-useless-template-attributes": "error"
      }
    },
  },
});
vp run lint

Bad

The conditional template has a class, but this structural wrapper does not render a DOM element to receive it.

<template>
<section><template v-if="ready" class="notice"><p>Ready</p></template></section>
</template>

Good

The class moves to the paragraph that actually renders while v-if stays on the structural template.

<template>
<section><template v-if="ready"><p class="notice">Ready</p></template></section>
</template>

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

Implementation · All rules

vue/no-useless-v-bind

Disallow a v-bind whose value is a plain string literal

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": {
        "vue/no-useless-v-bind": "warn"
      }
    },
  },
});
vp run lint

Bad

The foo binding evaluates a constant quoted string or a template string without interpolation.

<template>
<div :foo="'bar'"></div>
<div :foo="`bar`"></div>
</template>

Good

The constant value becomes a static attribute; variable and interpolated values retain their binding.

<template>
<div foo="bar"></div>
<div :foo="bar"></div>
<div :foo="`pre-${bar}`"></div>
</template>

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

Implementation · All rules

vue/no-v-for-template-key-on-child

Disallow key on the child of a <template v-for>

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": {
        "vue/no-v-for-template-key-on-child": "error"
      }
    },
  },
});
vp run lint

Bad

The child paragraph has the key while the template iteration itself has no key.

<template>
<template v-for="item in items"><p :key="item.id">{{ item.name }}</p></template>
</template>

Good

The key moves to template v-for, identifying the complete repeated fragment.

<template>
<template v-for="item in items" :key="item.id"><p>{{ item.name }}</p></template>
</template>

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

Implementation · All rules

vue/no-v-html

Warn against v-html to prevent XSS vulnerabilities

Bad · Good

Default severity: warning
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": {
        "vue/no-v-html": "warn"
      }
    },
  },
});
vp run lint

Bad

v-html interprets content as HTML rather than ordinary text.

<template>
  <article v-html="content" />
</template>

Good

Mustache interpolation displays content as escaped text instead of injecting HTML.

<template>
  <article>{{ content }}</article>
</template>

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

Implementation · All rules

vue/no-v-text

Disallow the v-text directive; prefer mustache interpolation

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": {
        "vue/no-v-text": "warn"
      }
    },
  },
});
vp run lint

Bad

The div's content is supplied through the v-text directive.

<template>
<div v-text="message"></div>
</template>

Good

Mustache interpolation expresses the same text binding directly in the element content.

<template>
<div>{{ message }}</div>
</template>

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

Implementation · All rules

vue/no-v-text-v-html-on-component

Disallow v-text / v-html on component elements

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": {
        "vue/no-v-text-v-html-on-component": "error"
      }
    },
  },
});
vp run lint

Bad

The component tag receives v-html or v-text, which replaces element content rather than supplying component slots.

<template>
  <MyComponent v-html="content" />
  <MyComponent v-text="content" />
</template>

Good

Native HTML targets can receive the directives; MyComponent receives its content through the default slot.

<template>
  <div v-html="content"></div>
  <component is="div" v-html="content" />
  <MyComponent>{{ content }}</MyComponent>
</template>

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

Implementation · All rules

vue/permitted-contents

Enforce HTML content model rules

Bad · Good

Default severity: error
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": {
        "vue/permitted-contents": "error"
      }
    },
  },
});
vp run lint

Bad

The examples put block content in p, omit the table body, nest interactive controls, or put a div directly inside ul.

<template>
  <p><div>block in a paragraph</div></p>
  <table><tr><td>row without tbody</td></tr></table>
  <a href="#"><button type="button">nested control</button></a>
  <ul><div>not a list item</div></ul>
</template>

Good

The examples use inline paragraph content, an explicit tbody, and li children. The custom MyItem is not treated as a known native ul child.

<template>
  <p><span>inline in a paragraph</span></p>
  <table><tbody><tr><td>cell</td></tr></tbody></table>
  <ul><li>list item</li><MyItem /></ul>
</template>

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

Implementation · All rules

vue/prefer-props-shorthand

Recommend shorthand syntax for props (Vue 3.4+)

Bad · Good

Default severity: warning
Presets: nuxt, opinionated
Automatic fix: Available for supported findings
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": {
        "vue/prefer-props-shorthand": "warn"
      }
    },
  },
});
vp run lint

Bad

Each binding repeats the corresponding variable name, including the camelCase equivalent of a hyphenated argument.

<template>
  <MyComponent :foo="foo" />
  <MyComponent :user-name="userName" />
  <span :style="style" />
  <div :aria-label="ariaLabel" />
</template>

Good

Vue 3.4+ same-name binding shorthand removes the repeated expressions; a different source variable such as bar remains explicit.

<template>
  <MyComponent :foo />
  <MyComponent :user-name />
  <span :style />
  <div :aria-label />
  <MyComponent :foo="bar" />
</template>

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

Implementation · All rules

vue/prefer-true-attribute-shorthand

Prefer the shorthand for a boolean attribute bound to true

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": {
        "vue/prefer-true-attribute-shorthand": "warn"
      }
    },
  },
});
vp run lint

Bad

A native boolean disabled attribute binds the constant true value.

<template>
<input :disabled="true" />
</template>

Good

The native attribute uses its boolean shorthand. False bindings and component props retain their explicit values.

<template>
<input disabled />
<input :disabled="false" />
<MyComponent :visible="true" />
<MyComponent :visible="isVisible" />
</template>

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

Implementation · All rules

vue/prop-name-casing

Enforce a casing for declared prop names

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.

Checks declared prop names, not the casing of attributes passed to a child.

Configuration (Vite+)

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

export default defineConfig({
  lint: {
    vize: {
      "preset": "incremental",
      "rules": {
        "vue/prop-name-casing": "warn"
      }
    },
  },
});
vp run lint

Bad

The declared prop name user_name uses underscore-separated spelling.

<script setup lang="ts">
defineProps<{ user_name: string }>();
</script>
<template><p>{{ user_name }}</p></template>

Good

The declaration and its template reference use the camelCase name userName.

<script setup lang="ts">
defineProps<{ userName: string }>();
</script>
<template><p>{{ userName }}</p></template>

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

Implementation · All rules

vue/require-component-is

Require v-bind:is on <component> elements

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": {
        "vue/require-component-is": "error"
      }
    },
  },
});
vp run lint

Bad

The dynamic <component> has no is target, so Vue cannot choose a component to render.

<template>
  <component />
</template>

Good

:is="currentComponent" supplies the component selection; the binding may change at runtime.

<template>
  <component :is="currentComponent" />
</template>

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

Implementation · All rules

vue/require-component-registration

Require explicit import or registration for components

Bad · Good

Default severity: warning
Presets: 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.

List explicit component names supplied by application plugins or Musea previewSetup. PascalCase and kebab-case spellings are accepted; regular expressions are not interpreted. Options do not enable the rule. Later layers replace the list; an empty list clears inherited names.

Configuration (Vite+)

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

export default defineConfig({
  lint: {
    vize: {
      "preset": "incremental",
      "rules": {
        "vue/require-component-registration": "warn"
      },
      "ruleOptions": {
        "vue/require-component-registration": {
          "globals": [
            "MyButton",
            "MyIcon"
          ]
        }
      }
    },
  },
});
vp run lint

Bad

MissingWidget is neither registered nor included in the configured global-component allowlist.

<template>
<MissingWidget />
</template>

Good

MyButton is listed in the example's globals option. That option exempts a known global component; it does not register or import it.

<template>
<MyButton />
</template>

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

Implementation · All rules

vue/require-scoped-style

Require scoped attribute on style tags

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": {
        "vue/require-scoped-style": "warn"
      }
    },
  },
});
vp run lint

Bad

The .button style is unscoped and can affect matching elements outside this component.

<style>
.button {
  color: red;
}
</style>

Good

Adding scoped applies Vue's component scope to the same selector and declarations.

<style scoped>
.button {
  color: red;
}
</style>

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

Implementation · All rules

vue/require-toggle-inside-transition

Require a toggle on the element wrapped by <transition>

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": {
        "vue/require-toggle-inside-transition": "error"
      }
    },
  },
});
vp run lint

Bad

The static child inside <Transition> has no conditional visibility or dynamic selection to trigger an enter/leave change.

<template>
<transition>
<div>content</div>
</transition>
</template>

Good

v-if="show" changes whether the child exists, giving the transition an enter/leave boundary.

<template>
<transition>
<div v-if="show">content</div>
</transition>
</template>

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

Implementation · All rules

vue/require-v-for-key

Require v-bind:key with v-for directives

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": {
        "vue/require-v-for-key": "error"
      }
    },
  },
});
vp run lint

Bad

Each repeated <li> lacks a key that identifies its corresponding item during list updates.

<template>
  <li v-for="item in items">{{ item.name }}</li>
</template>

Good

:key="item.id" gives each repeated node the item's identity rather than its current position.

<template>
  <li v-for="item in items" :key="item.id">{{ item.name }}</li>
</template>

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

Implementation · All rules

vue/scoped-event-names

Recommend scoped event names using context:event format

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": {
        "vue/scoped-event-names": "warn"
      }
    },
  },
});
vp run lint

Bad

playAudio, pauseAudio, and reloadAudio encode their scope as camel-case suffixes rather than the rule's colon-separated event convention.

<template>
  <AudioPlayer
    @playAudio="play"
    @pauseAudio="pause"
    @reloadAudio="reload"
  />
</template>

Good

audio:play, audio:pause, and audio:reload share an explicit audio: scope. The emitting component must use the same names.

<template>
  <AudioPlayer
    @audio:play="play"
    @audio:pause="pause"
    @audio:reload="reload"
  />
</template>

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

Implementation · All rules

vue/sfc-element-order

Enforce consistent order of SFC top-level 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: See typed options and defaults.

Configuration (Vite+)

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

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

Bad

The style block precedes the script block, contrary to the configured SFC block order.

<style scoped>
.panel {
  color: red;
}
</style>
<script setup lang="ts">
const label = "Save";
</script>

Good

The blocks follow script → template → style. Projects can choose a different order through this rule's typed option.

<script setup lang="ts">
const label = "Save";
</script>

<template>
  <p>{{ label }}</p>
</template>

<style scoped>
p {
  color: red;
}
</style>

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

Implementation · All rules

vue/single-style-block

Recommend having a single style block

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": {
        "vue/single-style-block": "warn"
      }
    },
  },
});
vp run lint

Bad

The component splits its scoped panel and title styles across two style blocks.

<style scoped>
.panel {
  color: red;
}
</style>

<style scoped>
.title {
  color: blue;
}
</style>

Good

Both selectors stay scoped in one style block, satisfying the single-block convention without dropping either style.

<style scoped>
.panel {
  color: red;
}
.title {
  color: blue;
}
</style>

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

Implementation · All rules

vue/slot-name-casing

Enforce kebab-case for named slots used via v-slot

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": {
        "vue/slot-name-casing": "warn"
      }
    },
  },
});
vp run lint

Bad

The named slot mySlot uses camelCase where the rule requires a hyphenated name.

<template>
<MyCard><template #mySlot>Content</template></MyCard>
</template>

Good

#my-slot uses kebab-case. Rename the corresponding slot outlet to the same name.

<template>
<MyCard><template #my-slot>Content</template></MyCard>
</template>

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

Implementation · All rules

vue/this-in-template

Disallow this. in template expressions

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": {
        "vue/this-in-template": "warn"
      }
    },
  },
});
vp run lint

Bad

Template expressions explicitly access this.message, this.className, and this.handleClick, although Vue exposes those bindings directly.

<template>
<div>{{ this.message }}</div>
<div :class="this.className"></div>
<button @click="this.handleClick()"></button>
</template>

Good

Use message, className, and handleClick directly. The literal string 'this.is.a.string' stays unchanged because it is not a member access.

<template>
<div>{{ message }}</div>
<div :class="className"></div>
<button @click="handleClick()"></button>
<div>{{ 'this.is.a.string' }}</div>
</template>

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

Implementation · All rules

vue/use-unique-element-ids

Enforce unique element IDs using useId() instead of static literals

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": {
        "vue/use-unique-element-ids": "warn"
      }
    },
  },
});
vp run lint

Bad

The literal email ID is reused by every instance of this component, which can misdirect its label when several instances are rendered.

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

Good

useId() produces the instance's emailId; bind the same value to the label's for and the input's id.

<script setup>
import { useId } from "vue";

const emailId = useId();
</script>

<template>
  <label :for="emailId">Email</label>
  <input :id="emailId" />
</template>

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

Implementation · All rules

vue/use-v-on-exact

Enforce .exact modifier on v-on when there are modifier-based handlers

Bad · Good

Default severity: warning
Presets: essential, 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": {
        "vue/use-v-on-exact": "warn"
      }
    },
  },
});
vp run lint

Bad

The plain click handler can also run on Ctrl-click, overlapping the separate .ctrl handler.

<template>
  <button type="button" @click="handleClick" @click.ctrl="handleCtrlClick">
    Save
  </button>
</template>

Good

.exact limits the ordinary click handler to clicks without modifier keys; the Ctrl-specific handler remains separate.

<template>
  <button
    type="button"
    @click.exact="handleClick"
    @click.ctrl="handleCtrlClick"
  >
    Save
  </button>
</template>

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

Implementation · All rules

vue/v-bind-style

Enforce v-bind directive style

Bad · Good

Default severity: warning
Presets: nuxt, opinionated
Automatic fix: Available for supported findings
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": {
        "vue/v-bind-style": "warn"
      }
    },
  },
});
vp run lint

Bad

v-bind:class uses the long form where the configured binding style requires the colon shorthand.

<template>
  <div v-bind:class="panelClass"></div>
</template>

Good

:class retains the same expression with the required shorthand; this rule concerns spelling rather than the value's type.

<template>
  <div :class="panelClass"></div>
</template>

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

Implementation · All rules

vue/v-on-event-hyphenation

Enforce hyphenation of custom event names in v-on on components

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: See typed options and defaults.

Configuration (Vite+)

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

export default defineConfig({
  lint: {
    vize: {
      "preset": "incremental",
      "rules": {
        "vue/v-on-event-hyphenation": "warn"
      }
    },
  },
});
vp run lint

Bad

The custom component listener uses @myEvent instead of a hyphenated event name.

<template>
<MyComponent @myEvent="handler" />
<MyComponent v-on:myEvent="handler" />
</template>

Good

@my-event uses the required custom-event spelling. Native-element listeners and dynamic event arguments shown below are outside this check.

<template>
<MyComponent @my-event="handler" />
<div @myEvent="handler" />
<MyComponent @[dynamicEvent]="handler" />
</template>

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

Implementation · All rules

vue/v-on-handler-style

Enforce writing v-on handlers as a method reference or an inline function

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": {
        "vue/v-on-handler-style": "warn"
      }
    },
  },
});
vp run lint

Bad

The handlers put mutations and multiple statements directly in the event attribute.

<template>
<button @click="count++"></button>
<button @click="doThis(); doThat()"></button>
<button @click="foo = bar"></button>
</template>

Good

Use a handler reference, or an arrow/function expression when inline logic is needed. The function boundary makes the handler form explicit.

<template>
<button @click="handler"></button>
<button @click="foo.bar"></button>
<button @click="() => count++"></button>
<button @click="function () { count++ }"></button>
</template>

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

Implementation · All rules

vue/v-on-style

Enforce v-on directive style

Bad · Good

Default severity: warning
Presets: happy-path, nuxt, ecosystem, opinionated
Automatic fix: Available for supported findings
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": {
        "vue/v-on-style": "warn"
      }
    },
  },
});
vp run lint

Bad

v-on:click uses the long event-listener form where the rule requires shorthand.

<template>
  <div v-on:click="handleClick"></div>
</template>

Good

@click keeps the same handler while using the configured shorthand.

<template>
  <div @click="handleClick"></div>
</template>

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

Implementation · All rules

vue/v-slot-style

Enforce v-slot directive style

Bad · Good

Default severity: warning
Presets: happy-path, nuxt, ecosystem, opinionated
Automatic fix: Available for supported findings
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": {
        "vue/v-slot-style": "warn"
      }
    },
  },
});
vp run lint

Bad

The component uses #default and the template uses v-slot:header, opposite to the rule's context-specific styles.

<template>
  <MyComponent #default="props">{{ props.item }}</MyComponent>
  <MyComponent>
    <template v-slot:header>Header</template>
  </MyComponent>
</template>

Good

Use v-slot for the component's default slot and #header for the template's named slot.

<template>
  <MyComponent v-slot="props">{{ props.item }}</MyComponent>
  <MyComponent>
    <template #header>Header</template>
  </MyComponent>
</template>

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

Implementation · All rules

vue/valid-attribute-name

Require valid attribute names

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.

Bad diagnostic: parser/template

Malformed attribute spelling is diagnosed by parser/template before this defensive rule sees an attribute. Bad therefore reports parser/template; it does not promise a separate vue/valid-attribute-name finding.

Configuration (Vite+)

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

export default defineConfig({
  lint: {
    vize: {
      "preset": "incremental",
      "rules": {
        "vue/valid-attribute-name": "error"
      }
    },
  },
});
vp run lint

Bad

The quote inside my"attr makes the attribute name malformed. This example produces the parser's parser/template diagnostic rather than promising a separate rule diagnostic.

<template>
<div my"attr="value"></div>
</template>

Good

my-attr is a well-formed attribute name, so the template parser can read the attribute and its value.

<template>
<div my-attr="value"></div>
</template>

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

Implementation · All rules

vue/valid-template-root

Enforce a valid <template> root for Vue 3 fragment semantics

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": {
        "vue/valid-template-root": "error"
      }
    },
  },
});
vp run lint

Bad

A plain nested <template> occupies the template root without a directive that gives it a rendering role.

<template>
<template>content</template>
</template>

Good

The <div> is a renderable root element. This example does not impose a universal single-root restriction on Vue 3 fragments.

<template>
<div>content</div>
</template>

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

Implementation · All rules

vue/valid-v-bind

Enforce valid v-bind directives

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": {
        "vue/valid-v-bind": "error"
      }
    },
  },
});
vp run lint

Bad

The bare v-bind has no object expression, and the empty argument form has no attribute name.

<template>
  <div v-bind></div>
  <div :></div>
</template>

Good

Provide an attribute and expression, bind an object, or use Vue 3.4+ same-name shorthand such as :loading.

<template>
  <div :class="panelClass"></div>
  <div v-bind="{ class: panelClass }"></div>
  <div :loading></div>
</template>

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

Implementation · All rules

vue/valid-v-cloak

Enforce valid v-cloak directives

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": {
        "vue/valid-v-cloak": "error"
      }
    },
  },
});
vp run lint

Bad

v-cloak is given a value, argument, or modifier even though it accepts none of those.

<template>
<div v-cloak="foo"></div>
<div v-cloak:arg></div>
<div v-cloak.mod></div>
</template>

Good

Use bare v-cloak; CSS can hide the element until Vue removes that attribute after mounting.

<template>
<div v-cloak></div>
</template>

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

Implementation · All rules

vue/valid-v-else

Enforce valid v-else directives

Bad · Good

Default severity: error
Presets: essential, happy-path, nuxt, ecosystem, opinionated
Automatic fix: Available for supported findings
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": {
        "vue/valid-v-else": "error"
      }
    },
  },
});
vp run lint

Bad

The examples give v-else an expression, combine it with v-if, or omit its adjacent preceding conditional branch.

<template>
  <div v-else="ready"></div>
  <div v-else v-if="ready"></div>
  <div v-else></div>
</template>

Good

Place bare v-else immediately after the corresponding v-if branch.

<template>
  <div v-if="ready"></div>
  <div v-else></div>
</template>

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

Implementation · All rules

vue/valid-v-for

Enforce valid v-for directives

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": {
        "vue/valid-v-for": "error"
      }
    },
  },
});
vp run lint

Bad

The loops omit their iteration expression or add an unsupported .stop modifier.

<template>
  <div v-for></div>
  <div v-for=""></div>
  <div v-for.stop="item in items"></div>
</template>

Good

Use item in items or (item, index) of items with a complete iteration expression and the shown keys.

<template>
  <div v-for="item in items" :key="item.id"></div>
  <div v-for="(item, index) of items" :key="index"></div>
</template>

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

Implementation · All rules

vue/valid-v-html

Enforce valid v-html directives

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": {
        "vue/valid-v-html": "error"
      }
    },
  },
});
vp run lint

Bad

v-html lacks its expression or uses an argument/modifier that this directive does not support.

<template>
<div v-html></div>
<div v-html:arg="foo"></div>
<div v-html.mod="foo"></div>
</template>

Good

v-html="html" supplies a valid expression. Syntax validity does not sanitize HTML or make untrusted content safe.

<template>
<div v-html="html"></div>
</template>

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

Implementation · All rules

vue/valid-v-if

Enforce valid v-if directives

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": {
        "vue/valid-v-if": "error"
      }
    },
  },
});
vp run lint

Bad

The conditions omit an expression or combine v-if with an else directive on the same node.

<template>
  <div v-if></div>
  <div v-if=""></div>
  <div v-if="ready" v-else></div>
</template>

Good

Each v-if has a nonempty condition such as ready or count > 0, without an incompatible else directive.

<template>
  <div v-if="ready"></div>
  <div v-if="count > 0"></div>
</template>

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

Implementation · All rules

vue/valid-v-memo

Enforce valid v-memo directives

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": {
        "vue/valid-v-memo": "error"
      }
    },
  },
});
vp run lint

Bad

Bare v-memo gives Vue no dependency expression for deciding when to reuse the subtree.

<template>
  <div v-memo></div>
</template>

Good

v-memo="[valueA, valueB]" supplies the dependency array used for memoization.

<template>
  <div v-memo="[valueA, valueB]">{{ label }}</div>
</template>

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

Implementation · All rules

vue/valid-v-model

Enforce valid v-model directives

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": {
        "vue/valid-v-model": "error"
      }
    },
  },
});
vp run lint

Bad

A native <div> cannot use v-model as a form control, and a bare input directive has no writable target expression.

<template>
  <div v-model="value"></div>
  <input v-model />
</template>

Good

Bind the input, select, textarea, or custom component to the shown writable variables.

<template>
  <input v-model="value" />
  <select v-model="selected"></select>
  <textarea v-model="text"></textarea>
  <MyInput v-model="value" />
</template>

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

Implementation · All rules

vue/valid-v-on

Enforce valid v-on directives

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": {
        "vue/valid-v-on": "error"
      }
    },
  },
});
vp run lint

Bad

The listener forms omit an event argument or their required handler/object expression.

<template>
  <div v-on></div>
  <div @></div>
  <div @click></div>
</template>

Good

Use an event with its handler, or pass a listener object to argument-free v-on.

<template>
  <div @click="handleClick"></div>
  <div v-on="{ click: handleClick }"></div>
</template>

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

Implementation · All rules

vue/valid-v-once

Enforce valid v-once directives

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": {
        "vue/valid-v-once": "error"
      }
    },
  },
});
vp run lint

Bad

v-once has a value, argument, or modifier, although this directive is a value-free render-once marker.

<template>
<div v-once="foo"></div>
<div v-once:arg></div>
<div v-once.mod></div>
</template>

Good

Bare v-once marks the subtree for one-time rendering without unsupported syntax.

<template>
<div v-once></div>
</template>

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

Implementation · All rules

vue/valid-v-show

Enforce valid v-show directives

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": {
        "vue/valid-v-show": "error"
      }
    },
  },
});
vp run lint

Bad

v-show lacks its visibility expression or is placed on a <template> that has no DOM element whose display can be changed.

<template>
  <div v-show></div>
  <template v-show="ready"><div></div></template>
</template>

Good

Apply the visibility expression to a rendered element such as <div>.

<template>
  <div v-show="ready"></div>
  <div v-show="count > 0"></div>
</template>

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

Implementation · All rules

vue/valid-v-slot

Enforce valid v-slot directives

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: See typed options and defaults.

Configuration (Vite+)

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

export default defineConfig({
  lint: {
    vize: {
      "preset": "incremental",
      "rules": {
        "vue/valid-v-slot": "error"
      }
    },
  },
});
vp run lint

Bad

The slot directive is on a native <div> or conflicts with other default/named slot declarations.

<template>
  <div v-slot:header></div>
  <MyComponent v-slot v-slot:header />
  <template v-slot:header v-slot:footer />
</template>

Good

Declare a component's default slot on that component, or its named slot on a child <template #header>.

<template>
  <MyComponent v-slot="{ item }">{{ item }}</MyComponent>
  <MyComponent>
    <template #header>Header</template>
  </MyComponent>
</template>

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

Implementation · All rules

vue/valid-v-text

Enforce valid v-text directives

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": {
        "vue/valid-v-text": "error"
      }
    },
  },
});
vp run lint

Bad

v-text lacks its text expression or uses an unsupported argument/modifier.

<template>
<div v-text></div>
<div v-text:arg="foo"></div>
<div v-text.mod="foo"></div>
</template>

Good

v-text="msg" is syntactically valid. The separate vue/no-v-text style rule can still prefer interpolation.

<template>
<div v-text="msg"></div>
</template>

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

Implementation · All rules

vue/warn-custom-block

Warn about custom blocks in SFC files

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": {
        "vue/warn-custom-block": "warn"
      }
    },
  },
});
vp run lint

Bad

The SFC contains an <i18n> custom block, which needs an external integration beyond ordinary template/script/style processing.

<i18n>
{ "en": { "hello": "Hello" } }
</i18n>

<template>
  <p>{{ hello }}</p>
</template>

Good

The example uses standard template and script-setup blocks. This optional portability warning does not mean every custom block is invalid Vue.

<template>
  <p>{{ hello }}</p>
</template>

<script setup lang="ts">
const hello = "Hello";
</script>

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

Implementation · All rules

vue/warn-custom-directive

Warn about custom directives that need registration

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": {
        "vue/warn-custom-directive": "warn"
      }
    },
  },
});
vp run lint

Bad

v-focus, v-mask, and v-click-outside require project-specific directive implementations that this optional convention flags.

<template>
  <input v-focus />
  <input v-mask="'###-####'" />
  <div v-click-outside="handleClose"></div>
</template>

Good

The example uses built-in v-if, v-model, and v-on. A correctly registered custom directive can still be valid Vue when this policy is disabled.

<template>
  <div v-if="ready"></div>
  <input v-model="value" />
  <button type="button" @click="onClick">Save</button>
</template>

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

Implementation · All rules