Vue Rules: Components and Props
Every rule on this page includes its purpose, prerequisites, configuration, and complete Bad/Good examples. Highlighted lines show what changes; copying an example gives you the complete source. Each rule also states its current support limits.
| Rule | Examples | Purpose |
|---|---|---|
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/multi-word-component-names |
Bad · Good | Require component names to be multi-word |
vue/no-mutating-props |
Bad · Good | Disallow mutating component props |
vue/no-non-component-keep-alive-child |
Bad · Good | Disallow plain element wrappers directly below <KeepAlive> |
vue/no-reserved-component-names |
Bad · Good | Disallow the use of reserved names as component names |
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/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 |
All rules · Rule Options · ESLint migration map · Project checks · Attributes across components
vue/component-definition-name-casing
Enforce PascalCase or kebab-case for component definition names
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.
vue/component-name-in-template-casing
Enforce specific casing for component names in templates
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.
vue/multi-word-component-names
Require component names to be multi-word
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.
vue/no-mutating-props
Disallow mutating component props
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.
vue/no-non-component-keep-alive-child
Disallow plain element wrappers directly below <KeepAlive>
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-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.
vue/no-reserved-component-names
Disallow the use of reserved names as component names
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.
vue/no-unused-components
Disallow registering components that are not used inside templates
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.
vue/no-unused-properties
Disallow unused properties defined in defineProps
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.
vue/require-component-is
Require v-bind:is on <component> elements
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.
vue/require-component-registration
Require explicit import or registration for components
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.