Vize

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

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/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/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-non-component-keep-alive-child

Disallow plain element wrappers directly below <KeepAlive>

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-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-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-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/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