Vue Rules: Components and Props
Component naming, registration, dynamic components, and prop ownership. See all Vue rules for the complete reference and Vue Rule Options for configurable settings.
vue/no-mutating-props
Reports writes to props. The owning component should update the value through an event or a model binding.
Default severity: error
Presets: happy-path, nuxt, opinionated
Bad:
<script setup lang="ts">
const props = defineProps<{ count: number }>();
props.count++;
</script>
Good:
<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>
vue/no-unused-components
Reports locally registered components that never appear in the template.
Default severity: warning
Presets: happy-path, nuxt, opinionated
Bad:
<script setup lang="ts">
import UserAvatar from "./UserAvatar.vue";
</script>
<template>
<p>{{ user.name }}</p>
</template>
Good:
<script setup lang="ts">
import UserAvatar from "./UserAvatar.vue";
</script>
<template>
<UserAvatar :user="user" />
</template>
vue/no-unused-properties
Reports props declared through defineProps that are not used by the component.
Default severity: warning
Presets: happy-path, nuxt, opinionated
Bad:
<script setup lang="ts">
defineProps<{ title: string; description: string }>();
</script>
<template>
<h1>{{ title }}</h1>
</template>
Good:
<script setup lang="ts">
defineProps<{ title: string; description: string }>();
</script>
<template>
<h1>{{ title }}</h1>
<p>{{ description }}</p>
</template>
vue/require-component-is
Reports <component> without an is binding.
Default severity: error
Presets: essential, happy-path, nuxt, opinionated
Bad:
<template>
<component />
</template>
Good:
<template>
<component :is="currentComponent" />
</template>
vue/component-definition-name-casing
Reports component filenames that are neither PascalCase nor kebab-case.
MyComponent.vue and my-component.vue are both accepted. index.vue and
App.vue are accepted too.
Default severity: warning
Presets: happy-path, nuxt, opinionated
Bad:
myComponent.vue
my-Component.vue
Good:
MyComponent.vue
my-component.vue
index.vue
App.vue
vue/component-name-in-template-casing
Enforces component name casing in templates. The default is PascalCase.
Built-ins such as <slot> are left alone.
Default severity: warning
Presets: nuxt, opinionated
Bad:
<template>
<my-component />
<myComponent />
</template>
Good:
<template>
<MyComponent />
<RouterView />
<slot />
</template>
vue/multi-word-component-names
Requires the component filename to contain more than one word, so it cannot
collide with a present or future HTML element. App.vue is the exception.
Names used inside the template are not what this rule checks.
Default severity: error
Presets: essential, nuxt, opinionated
Bad:
Item.vue
Table.vue
Good:
TodoItem.vue
DataTable.vue
App.vue
vue/no-non-component-keep-alive-child
Reports a plain element directly below <KeepAlive>. Vue caches component
vnodes, so a native wrapper leaves the component uncached. A wrapper whose
only directive is v-show is ignored. v-show together with something that
changes identity, such as :key, is still reported.
Default severity: warning
Presets: none (opt-in)
Bad:
<template>
<KeepAlive>
<div v-if="ready">
<UserCard />
</div>
</KeepAlive>
</template>
Good:
<template>
<KeepAlive>
<UserCard v-if="ready" />
</KeepAlive>
<KeepAlive>
<div v-show="opened">
<UserCard />
</div>
</KeepAlive>
</template>
vue/no-reserved-component-names
Reports an explicit component name that is an HTML element, an SVG element,
or a Vue built-in. It reads the Options API name and
defineOptions({ name }). It does not read the filename, and using
<Transition> or <KeepAlive> in a template is fine.
Default severity: error
Presets: essential, happy-path, nuxt, opinionated
Bad:
<script>
export default {
name: "button",
};
</script>
<script setup lang="ts">
defineOptions({ name: "svg" });
</script>
Good:
<script setup lang="ts">
defineOptions({ name: "AppButton" });
</script>
<template>
<Transition>
<AppButton />
</Transition>
</template>
vue/require-component-registration
Reports a component used in the template that was not imported in
<script setup> and was not registered. Built-ins such as <component> and
<Transition> are ignored.
Default severity: warning
Presets: opinionated
Bad:
<script setup lang="ts">
// MyButton is never imported.
</script>
<template>
<MyButton>Save</MyButton>
</template>
Good:
<script setup lang="ts">
import MyButton from "./MyButton.vue";
</script>
<template>
<MyButton>Save</MyButton>
</template>