Skip to content

noVueVIfWithVFor (HTML)

Language HTML
biome.json
{
"linter": {
"rules": {
"correctness": {
"noVueVIfWithVFor": "error"
}
}
}
}

Disallow using v-if, v-else-if, or v-else and v-for directives on the same element.

There are two common cases where v-if and v-for on the same element can be tempting:

  • To filter items in a list (e.g. v-for="user in users" v-if="user.isActive"). In these cases, replace users with a new computed property that returns your filtered list (e.g. activeUsers).
  • To avoid rendering a list if it should be hidden (e.g. v-for="user in users" v-if="shouldShowUsers"). In these cases, move the v-if to a container element.

Putting v-else-if or v-else on the same element as v-for works, but the condition is checked before the loop runs, which is hard to tell when reading the template. Move the v-else-if or v-else to a wrapper element, such as a <template>.

<TodoItem
v-if="complete"
v-for="todo in todos"
:todo="todo"
/>
code-block.vue:3:5 lint/correctness/noVueVIfWithVFor ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

✖ Using v-if and v-for on the same element is discouraged.

1 │ <TodoItem
2 │ v-if="complete"
> 3 │ v-for="todo in todos"
│ ^^^^^^^^^^^^^^^^^^^^^
4 │ :todo="todo"
5 │ />

ℹ This v-if should be moved to the wrapper element, or you should use a computed property to filter the list instead.

1 │ <TodoItem
> 2 │ v-if="complete"
│ ^^^^^^^^^^^^^^^
3 │ v-for="todo in todos"
4 │ :todo="todo"

ℹ Using v-if and v-for on the same element can lead to unexpected behavior and performance issues.

<div v-if="loading">Loading...</div>
<TodoItem v-else v-for="todo in todos" :todo="todo" />
code-block.vue:2:18 lint/correctness/noVueVIfWithVFor ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

✖ Using v-else and v-for on the same element is discouraged.

1 │ <div v-if="loading">Loading...</div>
> 2 │ <TodoItem v-else v-for="todo in todos" :todo="todo" />
│ ^^^^^^^^^^^^^^^^^^^^^
3 │

ℹ Move this v-else to a wrapper element, such as a <template>.

1 │ <div v-if="loading">Loading...</div>
> 2 │ <TodoItem v-else v-for="todo in todos" :todo="todo" />
│ ^^^^^^
3 │

ℹ The v-else is checked before the v-for loop runs, which is hard to tell when reading the template.

<ul v-if="complete">
<TodoItem
v-for="todo in todos"
:todo="todo"
/>
</ul>
<div v-if="loading">Loading...</div>
<template v-else>
<TodoItem v-for="todo in todos" :todo="todo" />
</template>