Vue Rule Options
Vue rule option examples cover component name casing, prop mutation depth, SFC block order, self-closing tags, event names, and attribute casing. The main Rule Options page lists the complete option table, unknown-field behavior, and scoped replacement semantics. Declared prop casing is documented in Prop Rule Options.
vue/html-quotes
Use "double" or "single" as a compact quote-style option. The object form also accepts
avoidEscape; when it is true, an already quoted attribute containing the requested delimiter
keeps its existing quotes instead of adding an escape.
import { defineConfig } from "@vizejs/vite-plugin/vite-plus";
export default defineConfig({}).withVue({
linter: {
rules: { "vue/html-quotes": "warn" },
ruleOptions: {
"vue/html-quotes": { style: "single", avoidEscape: true },
},
},
});
Bad with this config:
<div class="card"></div>
Good with this config:
<div class="card" title="don't"></div>
The first value is safely fixed to class='card'; title="don't" remains unchanged.
Options configure the rule without enabling it.
vue/mustache-interpolation-spacing
Use "always" to require whitespace immediately inside both mustache delimiters, or "never"
to require tight interpolation delimiters. The default is "always".
import { defineConfig } from "@vizejs/vite-plugin/vite-plus";
export default defineConfig({}).withVue({
linter: {
rules: { "vue/mustache-interpolation-spacing": "warn" },
ruleOptions: { "vue/mustache-interpolation-spacing": "never" },
},
});
Bad with this config:
<p>{{ message }}</p>
Good with this config:
<p>{{message}}</p>
Both delimiter-adjacent spaces are reported and safely removed. Options configure the rule without enabling it.
vue/valid-v-slot
By default, static and dynamic slot arguments reject modifiers such as
#item.memo and #[name].memo. Enable allowModifiers when a component API
uses dotted slot names, as Vuetify data tables do:
import { defineConfig } from "vize/config";
export default defineConfig({
linter: {
rules: { "vue/valid-v-slot": "error" },
ruleOptions: {
"vue/valid-v-slot": { allowModifiers: true },
},
},
});
Allowed with this config:
<FancyPanel>
<template #item.memo="{ item }">{{ item.memo }}</template>
<template #[name].memo="slot">{{ slot }}</template>
</FancyPanel>
An argless v-slot.memo remains invalid with either setting. A dynamic name
such as #[slot.name]="slot" also remains invalid: the name is evaluated before
that slot's parameters exist. The option only changes modifier policy and does
not enable a disabled rule. An explicit allowModifiers: false in a matching
entry restores the default policy even when the root config allows modifiers.
vue/component-name-in-template-casing
Use this option when a project wants component tags in templates to be consistently PascalCase or
kebab-case. By default, it checks registered component names from <script setup> declarations
and direct components registrations. Unregistered tags and scriptless templates stay clear.
Use registeredComponentsOnly: false to check all custom tags, or globals: ["PrimaryButton"]
for explicitly registered global components. Global names are literal strings; regex patterns and
the ESLint ignores option remain unsupported. Native HTML, SVG, MathML, slot and dynamic
component tags are skipped.
import { defineConfig } from "@vizejs/vite-plugin/vite-plus";
export default defineConfig({}).withVue({
linter: {
rules: {
"vue/component-name-in-template-casing": "warn",
},
ruleOptions: {
"vue/component-name-in-template-casing": {
casing: "kebab-case",
},
},
},
});
Bad with the config above:
<script setup>
import PrimaryButton from "./PrimaryButton.vue";
</script>
<template>
<PrimaryButton />
</template>
Good:
<script setup>
import PrimaryButton from "./PrimaryButton.vue";
</script>
<template>
<primary-button />
</template>
vue/no-mutating-props
Use shallowOnly when a migration allows nested prop mutation for now but still forbids replacing
the prop binding itself. The default false reports both direct and nested mutations.
import { defineConfig } from "@vizejs/vite-plugin/vite-plus";
export default defineConfig({}).withVue({
linter: {
rules: {
"vue/no-mutating-props": "error",
},
ruleOptions: {
"vue/no-mutating-props": {
shallowOnly: true,
},
},
},
});
Bad with the config above:
<script setup>
const props = defineProps<{ count: number; settings: { dense: boolean } }>();
props.count = 2;
</script>
Good with the config above:
<script setup>
const props = defineProps<{ settings: { dense: boolean } }>();
props.settings.dense = true;
</script>
vue/sfc-element-order
Use this option when a project has a fixed SFC block order. A string is one rank; a nested array
means any listed block selector may appear at that rank. Supported built-in selectors are script,
script:not([setup]), script[setup], template, and style; other non-empty strings match
custom block names.
import { defineConfig } from "@vizejs/vite-plugin/vite-plus";
export default defineConfig({}).withVue({
linter: {
rules: {
"vue/sfc-element-order": "warn",
},
ruleOptions: {
"vue/sfc-element-order": {
order: ["template", "script:not([setup])", "script[setup]", "i18n", "style"],
},
},
},
});
Bad with the config above:
<style scoped></style>
<template></template>
<script setup></script>
Good:
<template></template>
<script setup></script>
<style scoped></style>
vue/html-self-closing
Use this option to choose self-closing style per element family. always requires empty elements
to self-close, never forbids self-closing tags, and any accepts both forms. Omitted nested
fields keep the Vize defaults.
import { defineConfig } from "@vizejs/vite-plugin/vite-plus";
export default defineConfig({}).withVue({
linter: {
rules: {
"vue/html-self-closing": "warn",
},
ruleOptions: {
"vue/html-self-closing": {
html: {
void: "always",
normal: "never",
component: "always",
},
svg: "always",
math: "always",
},
},
},
});
Bad with the config above:
<template>
<div />
<PrimaryButton></PrimaryButton>
</template>
Good:
<template>
<div></div>
<PrimaryButton />
</template>
vue/v-on-event-hyphenation
Use this option for static custom event listener names on components. always reports camelCase
listener arguments such as @saveItem; never reports hyphenated listener arguments. Native HTML
events, object syntax, and dynamic arguments are skipped.
See event listener options for ignore-list validation and overrides.
import { defineConfig } from "@vizejs/vite-plugin/vite-plus";
export default defineConfig({}).withVue({
linter: {
rules: {
"vue/v-on-event-hyphenation": "warn",
},
ruleOptions: {
"vue/v-on-event-hyphenation": { style: "always", ignore: ["update:"] },
},
},
});
Bad with the config above:
<template>
<PrimaryButton @saveItem="save" />
</template>
Good:
<template>
<PrimaryButton @save-item="save" />
<button @saveItem="save" />
</template>
vue/v-bind-style
Use this option to choose the authored binding-directive spelling. The default shorthand style
requires :class; longform requires v-bind:class. Both modes preserve arguments, modifiers,
and values when applying a fix. Longform also rewrites .title to v-bind:title.prop, retaining
explicit modifiers and their order. Object syntax such as v-bind="attrs" is left unchanged.
import { defineConfig } from "@vizejs/vite-plugin/vite-plus";
export default defineConfig({}).withVue({
linter: {
rules: {
"vue/v-bind-style": "warn",
},
ruleOptions: {
"vue/v-bind-style": "longform",
},
},
});
Bad with the config above:
<a :title.camel="title">Open</a>
Good:
<a v-bind:title.camel="title" v-bind="attrs">Open</a>
vue/v-on-style
Use this option to choose the authored event-directive spelling. The default shorthand style
requires @click; longform requires v-on:click. Both modes preserve arguments and modifiers
when applying a fix. Object syntax such as v-on="listeners" has no interchangeable shorthand and
is therefore left unchanged.
import { defineConfig } from "@vizejs/vite-plugin/vite-plus";
export default defineConfig({}).withVue({
linter: {
rules: {
"vue/v-on-style": "warn",
},
ruleOptions: {
"vue/v-on-style": "longform",
},
},
});
Bad with the config above:
<button @click.stop="save">Save</button>
Good:
<button v-on:click.stop="save" v-on="listeners">Save</button>
vue/v-slot-style
Choose one spelling for every slot with "shorthand" or "longform", or use the object form to
set the component default slot, <template> default slot, and named slots independently. The
defaults are { atComponent: "v-slot", default: "shorthand", named: "shorthand" }. The bare
"v-slot" value is valid for atComponent and default, but not for named, because dropping a
named slot argument would change behavior. Safe fixes preserve slot arguments and values.
import { defineConfig } from "@vizejs/vite-plugin/vite-plus";
export default defineConfig({}).withVue({
linter: {
rules: {
"vue/v-slot-style": "warn",
},
ruleOptions: {
"vue/v-slot-style": {
atComponent: "longform",
default: "v-slot",
named: "longform",
},
},
},
});
Bad with the config above:
<MyPanel #default="slot"><template #header>Header</template>{{ slot.item }}</MyPanel>
Good:
<MyPanel v-slot:default="slot"><template v-slot:header>Header</template>{{ slot.item }}</MyPanel>