Skip to content

useVueValidVSlot (HTML)

Language HTML
biome.json
{
"linter": {
"rules": {
"nursery": {
"useVueValidVSlot": "error"
}
}
}
}

Enforce valid v-slot directives in Vue templates.

A v-slot directive (or its # shorthand) passes content to a slot of a component. Vue only accepts it in specific places, and a misplaced or duplicated v-slot is either rejected when the template is compiled or silently drops content.

This rule reports v-slot directives in the following cases:

  • The directive isn’t on a component, or on a <template> placed directly inside a component. For example, <div v-slot="props"></div>.
  • A named slot is written on the component itself instead of on a <template> inside it. For example, <MyComponent v-slot:header></MyComponent>.
  • The default slot is written on the component itself while the component also has <template> elements with v-slot.
  • An element has more than one v-slot directive.
  • Two <template> elements inside the same component fill the same slot. Elements in the same v-if, v-else-if, v-else sequence are allowed to fill the same slot, because only one of them is shown at a time.
  • A <template> with v-for fills a slot whose name doesn’t change between repetitions.
  • The directive has modifiers, such as v-slot.foo.
  • The default slot is written on the component itself without a value. For example, <MyComponent v-slot></MyComponent>.
<template>
<div v-slot="{ item }">{{ item }}</div>
</template>
code-block.vue:2:8 lint/nursery/useVueValidVSlot ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

✖ The v-slot directive must be used on a component, but <div> is not a component.

1 │ <template>
> 2 │ <div v-slot="{ item }">{{ item }}</div>
│ ^^^^^^^^^^^^^^^^^
3 │ </template>
4 │

ℹ Slots belong to components. Vue rejects v-slot anywhere else.

ℹ Move the directive to a component, or to a <template> placed directly inside a component.

ℹ This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information.

<template>
<MyComponent v-slot:header>Title</MyComponent>
</template>
code-block.vue:2:16 lint/nursery/useVueValidVSlot ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

✖ Named slots must use a <template> inside the component.

1 │ <template>
> 2 │ <MyComponent v-slot:header>Title</MyComponent>
│ ^^^^^^^^^^^^^
3 │ </template>
4 │

ℹ Only the default slot is meant to be written on the component itself. A named slot there is easy to mistake for the default slot.

ℹ Wrap the content in a <template> with this directive, and place it inside the component.

ℹ This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information.

<template>
<MyComponent v-slot="{ item }">
{{ item }}
<template #header>Title</template>
</MyComponent>
</template>
code-block.vue:2:16 lint/nursery/useVueValidVSlot ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

✖ The default slot must use a <template> when the component has other <template> slots.

1 │ <template>
> 2 │ <MyComponent v-slot="{ item }">
│ ^^^^^^^^^^^^^^^^^
3 │ {{ item }}
4 │ <template #header>Title</template>

ℹ Vue doesn't allow v-slot on the component itself when <template> elements inside it also use v-slot.

ℹ Move the default slot content into a <template #default> inside the component.

ℹ This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information.

<template>
<MyComponent>
<template #header>First title</template>
<template #header>Second title</template>
</MyComponent>
</template>
code-block.vue:4:15 lint/nursery/useVueValidVSlot ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

✖ This slot is already filled by another <template> in the same component.

2 │ <MyComponent>
3 │ <template #header>First title</template>
> 4 │ <template #header>Second title</template>
│ ^^^^^^^
5 │ </MyComponent>
6 │ </template>

ℹ The slot is first filled here.

1 │ <template>
2 │ <MyComponent>
> 3 │ <template #header>First title</template>
│ ^^^^^^^
4 │ <template #header>Second title</template>
5 │ </MyComponent>

ℹ A slot can receive content from only one <template>.

ℹ Remove one of the <template> elements, or give it another slot name. If only one of them should be shown at a time, use v-if and v-else.

ℹ This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information.

<template>
<MyComponent>
<template v-for="item in items" #header>{{ item }}</template>
</MyComponent>
</template>
code-block.vue:3:37 lint/nursery/useVueValidVSlot ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

✖ This <template> is repeated with v-for, but every repetition fills the same slot.

1 │ <template>
2 │ <MyComponent>
> 3 │ <template v-for="item in items" #header>{{ item }}</template>
│ ^^^^^^^
4 │ </MyComponent>
5 │ </template>

ℹ A slot can receive content from only one <template>, so only one of the repetitions is shown.

ℹ Use a slot name that changes with each item, such as #[item.name], or remove v-for.

ℹ This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information.

<template>
<MyComponent v-slot>Content</MyComponent>
</template>
code-block.vue:2:16 lint/nursery/useVueValidVSlot ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

✖ The v-slot directive on a component needs a value.

1 │ <template>
> 2 │ <MyComponent v-slot>Content</MyComponent>
│ ^^^^^^
3 │ </template>
4 │

ℹ Without a value, the directive has no effect: the content of the component already goes to its default slot.

ℹ Add the slot props you want to use, such as v-slot="{ item }", or remove the directive.

ℹ This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information.

<template>
<MyComponent v-slot="{ item }">{{ item }}</MyComponent>
<MyComponent>
<template #default="{ item }">{{ item }}</template>
<template #header>Title</template>
</MyComponent>
<MyComponent>
<template v-if="isAdmin" #header>Admin title</template>
<template v-else #header>Title</template>
</MyComponent>
<MyComponent>
<template v-for="item in items" #[item.slot]>{{ item.text }}</template>
</MyComponent>
</template>