Vue.js Two-way Data Binding (v-model directive)

Published on February 27, 2017 by

We just saw how we could update a data property’s value with the v-on directive and the keyup event. We did this both using a method as our event handler, and by embedding a JavaScript expression directly into our template. Not only was this code specifically handling text input fields, and would therefore not handle checkboxes, radio buttons, etc., it would also become pretty repetitive. Instead of writing this piece of code ourselves, fortunately there’s a better way; the v-model directive.

This directive implements two-way data binding for us. Two-way data binding means that changes to a data property updates the DOM, and changes made to the DOM will update the data property. So data flows both ways, hence the term “two-way data binding.”

Without further ado, let’s see an example. As you have probably noticed, I have prepared a text input which does nothing, and a data property called name. The v-model directive takes an expression, which will be the name of our data property – name in this case. So using the directive is as simply as writing the following.

<input type="text" v-model="name">

If I enter something into the text field, you will see that the data property is updated accordingly. Now that was easy, right? No more methods or inline JavaScript expressions within the template – at least not for accomplishing this.

Something you should note is that the v-model directive will ignore anything you have written inside the value attribute on an HTML element, because the data property always takes precedence. If I were to give the name property an initial value and add a value attribute at the same time, we will see that the value attribute is ignored.

new Vue({
	el: '#app',
	data: {
		name: 'Bo Andersen'
<input type="text" v-model="name" value="Test">

You might see a flicker where “Test” is displayed in the text input for a split second, before being replaced by the value of the name property. This is simply the time it takes for Vue.js to kick in; before then, whatever is in the value attribute is displayed as per normal HTML syntax.

I will just remove this test again.

I mentioned that the v-model directive supports other HTML elements as well. While this is indeed true, this is something that we will see later in the course when we begin working with forms.


There are a few modifiers available for the v-model directive. The first one I will show you is the trim modifier. This modifier does exactly what its name suggests; trim the user input.

<input type="text" v-model.trim="name">

With this, any leading or trailing spaces in the input field will be removed when the value is synchronized with the data property.

The second modifier I will show you is the number modifier, which ensures that the input is automatically casted to a number. You can think of this as the equivalent of calling the parseInt JavaScript function on the input. Let’s test that out.

Since we now need a data property that contains a number, I will add an age data property and use that in place of the name property. I will also remove the trim modifier.

<input type="text" v-model="age">
new Vue({
	el: '#app',
	data: {
		name: '',
		age: 27

To help with debugging our example, I will output the data type of the age property.

<p>Type: {{ typeof age }}</p>

If I run this example, you will see that the data type is initially number, because I specified an integer as the default value for the age property. If I type something in the input field, however, you will see that the data type changes to string. This is because the value of a text input field is always a string. If I add the number modifier, you will see that the value is casted to a number.

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

Typically you would use the number input type, though. With this input type, it appears that Vue.js automatically casts the value to a number (unlike with plain JavaScript), so the number modifier is not even necessary in this case. However, there may be situations where you need to use it, so now you know how it works and how to use it.

By default, the v-model directory synchronizes the input with data when the input event fires. If you want to change this to happen on the change event instead, you can do so by using the lazy modifier. So what’s the difference? The difference between these two events, is that the change event fires when an element’s data has been changed and the element loses its focus, whereas the input event fires every time data is changed. Right now, the data is updated every time I press a key because this triggers the input event. Now I will add the lazy modifier so that we can see the difference.

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

If I start typing in the input field now, we can see that the value is not updated. But the moment I click outside of the field, causing it to lose focus, the change event fires, and the data is synchronized.


In this post we took a look at the v-model directive, which can be used for two-way data binding, eliminating the need for writing custom methods and expressions to handle this. Apart from being easier and faster to use, there are a few added benefits of using the v-model directive. As we will see later in the course, the directive works with multiple input types automatically. It also handles certain edge cases, such as browser differences and such.


Learn Vue.js today!

Take an online course and become an Vue.js champion!

Here is what you will learn:

  • How to build advanced Vue.js applications (including SPA)
  • How Vue.js works under the hood
  • Communicating with services through HTTP
  • Managing state of large applications with Vuex
  • ... and much more!
Vue.js logo
Author avatar
Bo Andersen

About the Author

I am a back-end web developer with a passion for open source technologies. I have been a PHP developer for many years, and also have experience with Java and Spring Framework. I currently work full time as a lead developer. Apart from that, I also spend time on making online courses, so be sure to check those out!

Leave a Reply

Your e-mail address will not be published.