Using v-model for Two-Way Binding in Vue.js

Vue’s two-way binding system takes one of the trickiest parts of developing a web application, user input synchronization, and makes it dead simple with v-model. The v-model directive updates the template whenever the model changes and updates data model whenever the template changes.

Two-way binding is a powerful feature that, if used properly, can significantly speed up your development process. It reduces the complexity of keeping user input consistent with the application data model.

In Vue, two-way binding is accomplished using the v-model directive.

Binding to Text Input Elements

To bind the value of an input element to a property of your component’s data, use v-model="dataProperty" like so.

Here’s the component’s data method:

data() {   return {     existentialQuestion: 'Am I truly an alligator?'     }; } 

And the template:

<h2>My deepest, darkest question: {{existentialQuestion}}</h2> <input v-model="existentialQuestion"/> 

Here it is in a live demo:

See the Pen poyLjqY by alligatorio (@alligatorio) on CodePen.

Notice the input value starts out as Am I truly an alligator?, but when you change the input, the existentialQuestion property (and the h2 element) will update in real time.

Binding to Checkboxes and Radio Buttons

Checkboxes and radio buttons work pretty much like input elements. A checkbox binding will either be true or false, while a radio button binding will be whatever the contents of its value property is.

Additionally, a set of checkboxes can be bound to a single array, which will put the contents of their value property in the array if checked.

Single Checkbox Example

The component data…

data() {   return {     statementIsTrue: true     }; } 

…and the template

<p>You have decided this statement is {{statementIsTrue}}</p> <label>   <input type="checkbox" v-model="statementIsTrue"/>   Is this statement true? </label> 

…and try it live:

See the Pen abNYvxd by alligatorio (@alligatorio) on CodePen.

Multiple Checkbox Example

The component data…

data() {   return {     namesThatRhyme: []     }; } 

…and the template

<p>A list of names that rhyme: {{namesThatRhyme.join(', ')}}</p> <label>   <input type="checkbox" value="Daniel" v-model="namesThatRhyme"/>   Daniel </label> <label>   <input type="checkbox" value="Nathaniel" v-model="namesThatRhyme"/>   Nathaniel </label> <label>   <input type="checkbox" value="Hubert" v-model="namesThatRhyme"/>   Hubert </label> 

…and the demo:

See the Pen NWNYGZE by alligatorio (@alligatorio) on CodePen.

Radio Button Example

The component data…

  data() {     return {       howAreYouFeeling: "great"     };   } 

…and the template

<p>How are you feeling today?</p>   <label>     <input type="radio" value="great" v-model="howAreYouFeeling" />     great   </label>   <label>     <input type="radio" value="wonderful" v-model="howAreYouFeeling" />     wonderful   </label>   <label>     <input type="radio" value="fantastic" v-model="howAreYouFeeling" />     fantastic   </label>   <p>I am also feeling <em>{{howAreYouFeeling}}</em> today.</p> 

Here it is in a demo:

See the Pen gOreaVe by alligatorio (@alligatorio) on CodePen.


  • By default, v-model is evaluated every time the input event is fired (ie. on keypress or paste.) If you’d rather wait until the user has finished inputting and unfocused the field, you can use the v-model.lazy modifier to have v-model listen to the change event instead.
  • If you’d like to cast user input to a number instead of a string, add the v-model.number modifier. You’ll have to handle casting to other types yourself.
  • The v-model.trim modifier will strip and leading or trailing whitespace from the bound string. This (obviously) cannot be used in conjunction with v-model.number.
  • While v-model=“dataProperty” seems like magic at first glance, it’s actually just short-hand for :value="dataProperty" @input="dataProperty = $". As such, you can easily implement v-model support for your own components.