Skip to content

useVueValidVModel (HTML)

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

Enforce valid v-model directives.

v-model keeps a form field and a variable in sync: when the user types, Vue writes the new value back to the variable. This only works in some places, and only with a value that Vue can write to.

This rule reports v-model directives that:

  • are placed on an element other than <input>, <select>, <textarea>, or a component, such as <div v-model="foo">;
  • are placed on a file input, such as <input type="file" v-model="foo">; the browser doesn’t let code set the file of a file input;
  • have an argument on a native element, such as <input v-model:foo="bar">; only components accept an argument;
  • have a modifier other than .lazy, .number, or .trim on a native element, such as <input v-model.foo="bar">;
  • have no value, such as <input v-model>;
  • have a value that can’t be assigned to, such as <input v-model="foo + bar">;
  • read their value with optional chaining (?.), such as <input v-model="foo?.bar">;
  • read a property of a value that may be null or undefined, such as <input v-model="(foo?.bar).baz">;
  • write to a variable of a v-for or v-slot, such as <input v-for="item in items" v-model="item">; a new value for these variables wouldn’t reach the list or the slot data they were read from.
<template>
<div v-model="foo"></div>
</template>
code-block.vue:2:8 lint/nursery/useVueValidVModel ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

✖ The v-model directive can't be used on <div> elements.

1 │ <template>
> 2 │ <div v-model="foo"></div>
│ ^^^^^^^^^^^^^
3 │ </template>
4 │

ℹ Vue can only keep <input>, <select>, <textarea>, and components in sync with a variable.

ℹ Move the directive to a form field or a component, or bind the value with v-bind and listen for changes with v-on.

ℹ 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>
<input v-model:foo="bar" />
</template>
code-block.vue:2:17 lint/nursery/useVueValidVModel ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

✖ The v-model directive doesn't accept an argument on native elements.

1 │ <template>
> 2 │ <input v-model:foo="bar" />
│ ^^^^
3 │ </template>
4 │

ℹ Only components accept an argument, which names the prop to keep in sync.

ℹ Remove the argument.

ℹ 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>
<input v-model />
</template>
code-block.vue:2:10 lint/nursery/useVueValidVModel ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

✖ This v-model directive is missing a value.

1 │ <template>
> 2 │ <input v-model />
│ ^^^^^^^
3 │ </template>
4 │

ℹ The value names the variable that Vue keeps in sync with the field.

ℹ Add a value to the directive, e.g. v-model="message".

ℹ 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>
<input v-model="foo + bar" />
</template>
<template>
<input v-model="foo?.bar" />
</template>
<template>
<div v-for="todo in todos">
<input v-model="todo" />
</div>
</template>
<template>
<input v-model="foo" />
<input v-model.lazy="foo" />
<textarea v-model="foo"></textarea>
<MyComponent v-model="foo" />
<MyComponent v-model:propName.modifier="foo" />
<div v-for="todo in todos">
<input v-model="todo.name" />
</div>
</template>