Form Input Bindings

Basic Usage

You can use the v-model directive to create two-way data bindings on form input and textarea elements. It automatically picks the correct way to update the element based on the input type. Although a bit magical, v-model is essentially syntax sugar for updating data on user input events, plus special care for some edge cases.

v-model doesn’t care about the initial value provided to an input or a textarea. It will always treat the Vue instance data as the source of truth.

For languages that require an IME (Chinese, Japanese, Korean etc.), you’ll notice that v-model doesn’t get updated during IME composition. If you want to cater for these updates as well, use input event instead.

Text

<input v-model="message" placeholder="edit me">
<p>Message is: {{ message }}</p>

Message is: {{ message }}

Multiline text

<span>Multiline message is:</span>
<p style="white-space: pre">{{ message }}</p>
<br>
<textarea v-model="message" placeholder="add multiple lines"></textarea>
Multiline message is:

{{ message }}


Interpolation on textareas (<textarea>{{text}}</textarea>) won't work. Use v-model instead.

Checkbox

Single checkbox, boolean value:

<input type="checkbox" id="checkbox" v-model="checked">
<label for="checkbox">{{ checked }}</label>

Multiple checkboxes, bound to the same Array:

<input type="checkbox" id="jack" value="Jack" v-model="checkedNames">
<label for="jack">Jack</label>
<input type="checkbox" id="john" value="John" v-model="checkedNames">
<label for="john">John</label>
<input type="checkbox" id="mike" value="Mike" v-model="checkedNames">
<label for="mike">Mike</label>
<br>
<span>Checked names: {{ checkedNames }}</span>
new Vue({
el: '...',
data: {
checkedNames: []
}
})

Checked names: {{ checkedNames }}

Radio

<input type="radio" id="one" value="One" v-model="picked">
<label for="one">One</label>
<br>
<input type="radio" id="two" value="Two" v-model="picked">
<label for="two">Two</label>
<br>
<span>Picked: {{ picked }}</span>


Picked: {{ picked }}

Select

Single select:

<select v-model="selected">
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<span>Selected: {{ selected }}</span>
Selected: {{ selected }}

Multiple select (bound to Array):

<select v-model="selected" multiple>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<br>
<span>Selected: {{ selected }}</span>

Selected: {{ selected }}

Dynamic options rendered with v-for:

<select v-model="selected">
<option v-for="option in options" v-bind:value="option.value">
{{ option.text }}
</option>
</select>
<span>Selected: {{ selected }}</span>
new Vue({
el: '...',
data: {
selected: 'A',
options: [
{ text: 'One', value: 'A' },
{ text: 'Two', value: 'B' },
{ text: 'Three', value: 'C' }
]
}
})
Selected: {{ selected }}

Value Bindings

For radio, checkbox and select options, the v-model binding values are usually static strings (or booleans for checkbox):

<!-- `picked` is a string "a" when checked -->
<input type="radio" v-model="picked" value="a">
<!-- `toggle` is either true or false -->
<input type="checkbox" v-model="toggle">
<!-- `selected` is a string "abc" when selected -->
<select v-model="selected">
<option value="abc">ABC</option>
</select>

But sometimes we may want to bind the value to a dynamic property on the Vue instance. We can use v-bind to achieve that. In addition, using v-bind allows us to bind the input value to non-string values.

Checkbox

<input
type="checkbox"
v-model="toggle"
v-bind:true-value="a"
v-bind:false-value="b"
>
// when checked:
vm.toggle === vm.a
// when unchecked:
vm.toggle === vm.b

Radio

<input type="radio" v-model="pick" v-bind:value="a">
// when checked:
vm.pick === vm.a

Select Options

<select v-model="selected">
<!-- inline object literal -->
<option v-bind:value="{ number: 123 }">123</option>
</select>
// when selected:
typeof vm.selected // -> 'object'
vm.selected.number // -> 123

Modifiers

.lazy

By default, v-model syncs the input with the data after each input event (with the exception of IME composition as stated above). You can add the lazy modifier to instead sync after change events:

<!-- synced after "change" instead of "input" -->
<input v-model.lazy="msg" >

.number

If you want user input to be automatically typecast as a number, you can add the number modifier to your v-model managed inputs:

<input v-model.number="age" type="number">

This is often useful, because even with type="number", the value of HTML input elements always returns a string.

.trim

If you want user input to be trimmed automatically, you can add the trim modifier to your v-model managed inputs:

<input v-model.trim="msg">

v-model with Components

If you’re not yet familiar with Vue’s components, just skip this for now.

HTML’s built-in input types won’t always meet your needs. Fortunately, Vue components allow you to build reusable inputs with completely customized behavior. These inputs even work with v-model! To learn more, read about custom inputs in the Components guide.