Form input bindings with v-model

Vue · Essentials · 10 min

Forms are everywhere, and v-model removes the value-plus-listener boilerplate for each field.

`v-model` creates a two-way binding between a form element and a ref. It is sugar for a value binding plus an event listener, chosen per element type:

  • <input> and <textarea>: binds value and listens to input.
  • Checkbox: binds checked (a boolean). Several checkboxes bound to the same array collect the values of the checked ones.
  • Radio: the ref holds the value of the selected radio.
  • <select>: the ref holds the selected option's value, or an array with multiple.

Modifiers adjust the behaviour:

  • .trim strips whitespace.
  • .number casts the input to a number (when it parses).
  • .lazy syncs on change instead of every keystroke.

v-model ignores any initial value, checked or selected attributes in the template: the JavaScript state is the single source of truth, so set initial values in the ref.

Option values do not have to be strings: bind :value="obj" on options or checkboxes and the model receives the object itself.

For validation, keep it simple at first: a computed errors object derived from the fields, and a submit handler that checks it. Larger forms usually adopt a library such as VeeValidate or FormKit. You will later learn to make your own components work with v-model too.

Example

<script setup>
import { ref, computed } from 'vue'

const name = ref('')
const age = ref(null)
const agree = ref(false)
const toppings = ref(['cheese'])
const size = ref('m')
const canSubmit = computed(() => name.value && agree.value && age.value >= 18)
</script>

<template>
  <input v-model.trim="name" placeholder="Name">
  <input v-model.number="age" type="number">
  <label><input type="checkbox" v-model="agree"> I agree</label>
  <label><input type="checkbox" value="cheese" v-model="toppings"> Cheese</label>
  <label><input type="checkbox" value="ham" v-model="toppings"> Ham</label>
  <select v-model="size">
    <option value="s">Small</option><option value="m">Medium</option>
  </select>
  <pre>{{ { name, age, agree, toppings, size } }}</pre>
  <button :disabled="!canSubmit">Order</button>
</template>

Remember

  • v-model = value binding + input listener, adapted to each input type
  • Several checkboxes on one array ref collect the checked values
  • .trim, .number and .lazy modify the binding; initial values live in the ref

Watch out for

  • Setting value="..." or checked in the template and expecting it to be the initial state; v-model ignores it.

Check yourself

  1. Three checkboxes with values 'a', 'b', 'c' all use v-model="picked" where picked = ref([]). The user checks a and c. What is picked.value?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: vuejs.org/guide/essentials/forms.html