Menu
×
   ❮   
HTML CSS JAVASCRIPT SQL PYTHON JAVA PHP HOW TO W3.CSS C C++ C# BOOTSTRAP REACT MYSQL JQUERY EXCEL XML DJANGO NUMPY PANDAS NODEJS R TYPESCRIPT ANGULAR GIT POSTGRESQL MONGODB ASP AI GO KOTLIN SASS VUE DSA GEN AI SCIPY AWS CYBERSECURITY DATA SCIENCE
     ❯   

Vue Tutorial

Vue HOME Vue Intro Vue Directives Vue v-bind Vue v-if Vue v-show Vue v-for Vue Events Vue v-on Vue Methods Vue Event Modifiers Vue Forms Vue v-model Vue CSS Binding Vue Computed Properties Vue Watchers Vue Templates

Scaling Up

Vue Why, How and Setup Vue First SFC Page Vue Components Vue Props Vue v-for Components Vue $emit() Vue Fallthrough Attributes Vue Scoped Styling Vue Local Components Vue Slots Vue v-slot Vue Scoped Slots Vue Dynamic Components Vue Teleport Vue HTTP Request Vue Template Refs Vue Lifecycle Hooks Vue Provide/Inject Vue Routing Vue Form Inputs Vue Animations Vue Animations with v-for Vue Build Vue Composition API

Vue Reference

Vue Built-in Attributes Vue Built-in Components Vue Built-in Elements Vue Component Instance Vue Directives Vue Instance Options Vue Lifecycle Hooks

Vue Examples

Vue Examples Vue Exercises Vue Quiz Vue Server Vue Certificate

Vue v-model Directive


Example

Using the v-model directive to create a two-way binding between an <input> element and a data property.

<template>
  <h1>v-model Example</h1>
  <p>Write something, and see the 'inputValue' data property update automatically.</p>
  <input type="text" v-model="inputValue"> 
  <p>inputValue property: "{{ inputValue }}"</p>
</template>
Run Example »

See more examples below.


Definition and Usage

The v-model directive is used to create a two-way binding between a form input element, or between a Vue instance property and a component.


Form Input Elements with v-model

Form input elements that can be used with v-model are <input>, <select> and <textarea>.

Two-way binding with v-model on form input elements works like this:

  • When Vue detects a change in the input value, it will update the corresponding data property accordingly. (HTML -> JavaScript)
  • When Vue detects a change in a Vue instance property, it will update the corresponding input value accordingly. (JavaScript -> HTML)

(See Example above, and Example 1 below.)


Components with v-model

When v-model is used on a component, the component interface must be set up properly with props and emits to achieve the two-way binding.

Two-way binding with v-model on components works like this:

  • When Vue detects a change in the parent instance property, the new value is sent as a prop to the component.
  • When Vue detects a change in the child component, the new value is sent up to the parent as an emit event.

When v-model is used on a component, the default prop name is 'modelValue', and the default emit event name is 'update:modelValue'. (See Example 2 and Example 3.)

When v-model is used on a component, instead of using a Vue instance data property we can use a computed property with the get() and set() methods. (See Example 4)

Different names for props and emits than the default 'modelValue' and 'update:modelValue' can be set using v-model:. (See Example 5)

To have more than one value connected as two-way bindings to a component, we must define each such value with its own v-model. (See Example 6)


Modifiers

Modifiers Details
.lazy The change event is used by Vue instead of the input event for when to synchronize. This means that the user must first modify the input, and then switch focus away from the input element before the instance property value gets updated. (See Example 7)
.number Typecasts the input to number. This is done automatically when using <input type="number">.
.trim Removes white spaces at the start and end of the input. (See Example 8)
custom To create a custom modifier for v-model, we first need to define a prop 'modelModifiers' to store the new modifier. The modifier functionality is written in a method. If the modifier is set, the appropriate code runs in the method before emitting the value back up to the parent component. (See Example 9)


More Examples

Example 1

Using a slider (<input type="range">) to change the 'inputValue' property value. The <input type="text"> element automatically updates because it is bound to the 'inputValue' property with v-model.

<template>
  <h1>v-model Example</h1>
  <p>Drag the slider to change the 'inputValue' data property, and see the input text field update automatically because of the two-way binding from v-model.</p>
  <input type="range" min="-50" max="50" v-on:input="sliderChange" value="4">
  <p>inputValue property: "{{ inputValue }}"</p>
  <input type="text" v-model="inputValue"> 
</template>

<script>
export default {
  data() {
    return {
      inputValue: null
    };
  },
  methods: {
    sliderChange(evt) {
      this.inputValue = evt.target.value
    }
  }
}
</script>
Run Example »

Example 2

Using v-model on the component with props and emits so that changes in the <input> element updates the parent's 'text' property.

App.vue:

<template>
  <h2>Example v-model Directive</h2>
  <p>App.vue 'text' property: "{{ text }}"</p>
  <comp-one v-model="text"/>
</template>

<script>
export default {
  data() {
    return {
      text: 'Say Cheese'
    }
  }
}
</script>

CompOne.vue:

<template>
  <div>
    <h3>Component</h3>
    <p>Write something in the text input field below to see that changes here are emitted from the component, and the parent 'text' property gets updated by the use of v-model.</p>
    <input
      :value="modelValue"
      @input="$emit('update:modelValue', $event.target.value)"
    />
  </div>
</template>

<script>
  export default {
    props: ['modelValue'],
    emits: ['update:modelValue']
  }
</script>

<style scoped>
div {
  border: solid black 1px;
  padding: 10px;
  margin: 20px 0;
  max-width: 500px;
}
</style>
Run Example »

Example 3

Using v-model on the component to demonstrate the two-way binding more clearly. The component can update the parent 'text' property, and the component gets updated when the parent 'text' property is changed.

App.vue:

<template>
  <h2>Example v-model Directive</h2>
  <p>App.vue 'text' property: "<pre>{{ text }}</pre>"</p>
  <button v-on:click="this.text = 'Hello!'">text='Hello!'</button>
  <comp-one v-model="text"/>
</template>

<script>
export default {
  data() {
    return {
      text: 'Say Cheese'
    }
  }
}
</script>

<style>
pre {
  display: inline;
  background-color: yellow;
}
</style>

CompOne.vue:

<template>
  <div>
    <h3>Component</h3>
    <p>Two-way binding on component with v-model:</p>
    <ol>
      <li>The component can update the 'text' property (using text field).</li>
      <li>The component gets updated when the 'text' property is changed (using button).</li>
    </ol>
    <input
      :value="modelValue"
      @input="$emit('update:modelValue', $event.target.value)"
    />
  </div>
</template>

<script>
  export default {
    props: ['modelValue'],
    emits: ['update:modelValue']
  }
</script>

<style scoped>
div {
  border: solid black 1px;
  padding: 10px;
  margin: 20px 0;
  max-width: 600px;
}
</style>
Run Example »

Example 4

Using v-model with a computed value with get() and set() functions inside the component.

CompOne.vue:

<template>
  <div>
    <h3>Component</h3>
    <p>Two-way binding on component with v-model:</p>
    <ol>
      <li>The component can update the 'text' property (using text field).</li>
      <li>The component gets updated when the 'text' property is changed (using button).</li>
    </ol>
    <input v-model="inpVal"/>
  </div>
</template>

<script>
  export default {
    props: ['modelValue'],
    emits: ['update:modelValue'],
    computed: {
      inpVal: {
        get() {
          return this.modelValue;
        },
        set(inpVal) {
          this.$emit('update:modelValue',inpVal)
        }
      }
    }
  }
</script>

<style scoped>
div {
  border: solid black 1px;
  padding: 10px;
  margin: 20px 0;
  max-width: 600px;
}
</style>
Run Example »

Example 5

Using v-model:message on the component to rename the default prop name 'modelValue' to 'message'.

App.vue:

<template>
  <h2>Example v-model Directive</h2>
  <p>App.vue 'text' property: "<pre>{{ text }}</pre>"</p>
  <button v-on:click="this.text = 'Hello!'">text='Hello!'</button>
  <comp-one v-model:message="text"/>
</template>

<script>
export default {
  data() {
    return {
      text: 'Say Cheese'
    }
  }
}
</script>

<style>
pre {
  display: inline;
  background-color: yellow;
}
</style>

CompOne.vue:

<template>
  <div>
    <h3>Component</h3>
    <p>Two-way binding on component with v-model:</p>
    <ol>
      <li>The component can update the 'text' property (using text field).</li>
      <li>The component gets updated when the 'text' property is changed (using button).</li>
    </ol>
    <input
      :value="message"
      @input="$emit('update:message', $event.target.value)"
    />
  </div>
</template>

<script>
  export default {
    props: ['message'],
    emits: ['update:message']
  }
</script>

<style scoped>
div {
  border: solid black 1px;
  padding: 10px;
  margin: 20px 0;
  max-width: 600px;
}
</style>
Run Example »

Example 6

Using v-model two times on the component to create a two-way binding with two values.

App.vue:

<template>
  <h2>Example v-model Directive</h2>
  <p>Name: "<pre>{{ name }}</pre>"</p>
  <p>Height: <pre>{{ height }}</pre> cm</p>
  <comp-one 
    v-model:name="name"
    v-model:height="height"
  />
</template>

<script>
export default {
  data() {
    return {
      name: 'Olaf',
      height: 120
    }
  }
}
</script>

<style>
pre {
  display: inline;
  background-color: yellow;
}
</style>

CompOne.vue:

<template>
  <div>
    <h3>Component</h3>
    <p>Two inputs are bound to the component with v-model through props and emits.</p>
    <p>
      <label>
        Name: 
        <input
          type="text"
          :value="name"
          @input="$emit('update:name', $event.target.value)"
        />
      </label>
    </p>
    <p>
      <label>
        Height:
        <input
          type="range"
          :value="height"
          @input="$emit('update:height', $event.target.value)"
          min="50"
          max="200"
        />
        {{ this.$props.height }} cm
      </label>
    </p>
  </div>
</template>

<script>
  export default {
    props: ['name','height'],
    emits: ['update:name','update:height']
  }
</script>

<style scoped>
div {
  border: solid black 1px;
  padding: 10px;
  margin: 20px 0;
  max-width: 300px;
}
</style>
Run Example »

Example 7

Using the .lazy so that the user must first modify the input element, then change focus away from the input element before the property gets updated with v-model.

<template>
  <h1>v-model Example</h1>
  <p>Using the '.lazy' modifier, you must first write something, then click somewhere else, or use the tab key to switch focus away from the input element, before the property get updated.</p>
  <input type="text" v-model.lazy="inputValue"> 
  <p>inputValue property: "{{ inputValue }}"</p>
</template>

<script>
export default {
  data() {
    return {
      inputValue: null
    };
  }
}
</script>
Run Example »

Example 8

Using the .lazy so that the user must first modify the input element, then change focus away from the input element before the property gets updated with v-model.

<template>
  <h1>v-model Example</h1>
  <p>Using the '.trim' modifier will remove any white spaces at the start and end of the input.</p>
  <p>Add white spaces at the start and end in the input fields below to see the difference with or with out '.trim'.</p>
  <p>No '.trim': <input type="text" v-model="inputVal1"> "<pre>{{ inputVal1 }}</pre>"</p> 
  <p>With '.trim': <input type="text" v-model.trim="inputVal2"> "<pre>{{ inputVal2 }}</pre>"</p>
  
</template>

<script>
export default {
  data() {
    return {
      inputVal1: 'Hello',
      inputVal2: 'Hi'
    };
  }
}
</script>

<style>
pre {
  display: inline;
  background-color: lightgreen;

}
</style>
Run Example »

Example 9

Using the custom .allCapital modifier to convert all characters in the input to upper case if the .allCapital modifier is set.

App.vue:

<template>
  <h2>Example v-model Directive</h2>
  <p>App.vue 'text' property: "{{ text }}"</p>
  <comp-one v-model.allCapital="text"/>
</template>

<script>
export default {
  data() {
    return {
      text: ''
    }
  }
}
</script>

CompOne.vue:

<template>
  <div>
    <h3>Component</h3>
    <p>Write something in the text input field below. Click somewhere else or use the tab key to shift focus away from the input element to see the effect of the custom 'allCapital' modifier.</p>
    <input 
      :value="modelValue" 
      @change="this.emitVal" 
    />
  </div>
</template>

<script>
export default {
  props: {
    modelValue: String,
    modelModifiers: {
      // modelModifiers is an empty object initially.
      // Modifiers set on the component will be stored here.
      default: () => ({}) 
    }
  },
  emits: ['update:modelValue'],
  methods: {
    emitVal(e) {
      let value = e.target.value
      if (this.modelModifiers.allCapital) {
        value = value.toUpperCase()
      }
      this.$emit('update:modelValue', value)
    }
  }
}
</script>

<style scoped>
div {
  border: solid black 1px;
  padding: 10px;
  margin: 20px 0;
  max-width: 500px;
}
</style>
Run Example »

Related Pages

Vue Tutorial: Vue Components

Vue Tutorial: Vue Props

Vue Tutorial: Vue $emit() Method

Vue Tutorial: Vue Computed Properties

Vue Reference: Vue $emit() Method

Vue Reference: Vue $props Object

JavaScript Tutorial: JavaScript Object Accessors