vuejs-vmodel-binding-datos

Data binding with `v-model` in Vue.js

  • 6 min

In Vue.js, the v-model directive allows you to create a two-way binding between an HTML form element and a JavaScript variable in the Vue instance.

Two-way binding works in both directions, from the data in JavaScript to the HTML and vice versa.

That is,

  • Any change in the form element ➡️ will be reflected in the data
  • Any change in the data ➡️ will be reflected in the form element.

v-model Directive

As we said, the v-model directive allows for two-way binding that works between the JavaScript data and the HTML.

The binding occurs between a form element (like <input>, <textarea>, or <select>), which are the elements that can receive user data input.

Binding with v-model allows changes in the form element to be automatically reflected in the data, and vice versa.

<template>
  <input v-model="message" placeholder="Escribe algo" />
  <p>Mensaje: {{ message }}</p>
</template>

<script setup>
import { ref } from 'vue';

const message = ref('');
</script>
Copied!

In this example:

  • The text field value is bound to the message variable.
  • If the user types in the field, message is automatically updated.
  • If message changes in the script, the text field is automatically updated.

Under the hood v-model

<input v-model="message">
Copied!

Is basically the same as a value binding and a handler for input

<input :value="message" @input="event => message = event.target.value">
Copied!

Using v-model with Different Form Elements

v-model behaves (slightly) differently depending on the type of form element it is applied to.

Depending on the element we use it on, it will be,

ElementBound AttributeData TypeBehavior
<input> (text)valueStringThe input value is bound to the property. Updates bidirectionally.
<textarea>valueStringThe textarea content is bound to the property. Updates bidirectionally.
<select>value of the selected optionString (or array)The selected value is bound to the property. In multiple, it’s an array.
<input> (checkbox)checkedBoolean (or array if multiple)The checked state is bound to the property. In multiple, it’s an array.
<input> (radio)checkedStringThe value of the selected option is bound to the property. Only one option can be selected.

Vue handles the binding appropriately to ensure data is updated correctly in both directions.

<template>
  <input v-model="text" type="text" placeholder="Escribe algo" />
  <p>Texto ingresado: {{ text }}</p>
</template>

<script setup>
import { ref } from 'vue';

const text = ref('');
</script>
Copied!
<template>
  <textarea v-model="description" placeholder="Escribe una descripción"></textarea>
  <p>Descripción: {{ description }}</p>
</template>

<script setup>
import { ref } from 'vue';

const description = ref('');
</script>
Copied!
<template>
  <select v-model="selectedOption">
    <option value="opcion1">Opción 1</option>
    <option value="opcion2">Opción 2</option>
    <option value="opcion3">Opción 3</option>
  </select>
  <p>Opción seleccionada: {{ selectedOption }}</p>
</template>

<script setup>
import { ref } from 'vue';

const selectedOption = ref('opcion1');
</script>
Copied!
<template>
  <label>
    <input type="checkbox" v-model="isChecked" />
    ¿Estás de acuerdo?
  </label>
  <p>Estado del checkbox: {{ isChecked ? 'Sí' : 'No' }}</p>
</template>

<script setup>
import { ref } from 'vue';

const isChecked = ref(false);
</script>
Copied!

v-model Modifiers

v-model modifiers allow you to adjust the behavior of data synchronization between state and the DOM in Vue.js.

ModifierDescription
.lazyUpdates the value only after the change event occurs
.numberAutomatically converts the input value to a number
.trimRemoves whitespace from the beginning and end of the value.

The .lazy modifier makes v-model update the value only after the change event (instead of input).

<template>
  <input v-model.lazy="message" placeholder="Escribe algo" />
  <p>Mensaje: {{ message }}</p>
</template>

<script setup>
import { ref } from 'vue';

const message = ref('');
</script>
Copied!

In this example:

  • The value of message is updated only when the text field loses focus.

The .number modifier automatically converts the input to a number.

<template>
  <input v-model.number="age" type="number" placeholder="Edad" />
  <p>Edad: {{ age }} ({{ typeof age }})</p>
</template>

<script setup>
import { ref } from 'vue';

const age = ref(0);
</script>
Copied!

In this example:

  • The input is automatically converted to a number.

The .trim modifier removes whitespace from the beginning and end of the input.

<template>
  <input v-model.trim="username" placeholder="Nombre de usuario" />
  <p>Nombre de usuario: "{{ username }}"</p>
</template>

<script setup>
import { ref } from 'vue';

const username = ref('');
</script>
Copied!

In this example:

  • Whitespace at the beginning and end is automatically removed.

It is possible to combine several modifiers to achieve more precise behavior.

<input v-model.lazy.trim.number="amount" />
Copied!

Using v-bind in Our Components Advanced

v-model can also be used in our own components to create a two-way binding between the parent component and the child component.

CustomInput.vue

<template>
  <input :value="modelValue" @input="$emit('update:modelValue', $event.target.value)" />
</template>

<script setup>
defineProps({
  modelValue: String,
});

defineEmits(['update:modelValue']);
</script>
Copied!

ParentComponent.vue

<template>
  <CustomInput v-model="message" />
  <p>Mensaje: {{ message }}</p>
</template>

<script setup>
import { ref } from 'vue';
import CustomInput from './CustomInput.vue';

const message = ref('');
</script>
Copied!

In this example:

  • The child component (CustomInput) receives the modelValue prop and emits an update:modelValue event when the value changes.
  • The parent component uses v-model to bind message to the child component.
Copied!