AcademyVue
Form Input Bindings: v-model in Depth
v-model.trim, .number and .lazy fix the three most common form bugs, and a checkbox group binds to a shared array with no extra code.
2 min readUpdated 3 exercises
v-model already picks the right event and prop per element
v-model is sugar that expands differently depending on what it is bound to: a text <input> binds value and listens for input, a <textarea> does the same, a <select> binds value and listens for change, and a checkbox or radio binds checked and listens for change. You almost never need to know this — it is exactly the kind of detail v-model exists to hide — until a specific input type behaves in a way you did not expect.
.trim, .number and .lazy fix three specific, common bugs
<template>
<!-- .trim strips leading/trailing whitespace before it ever reaches the ref -->
<input v-model.trim="name" />
<!-- .number casts the string DOM value to a number — without it, even
type="number" inputs still give you a string through v-model -->
<input type="number" v-model.number="age" />
<!-- .lazy syncs on the change event instead of input — once the field
loses focus, not on every keystroke -->
<input v-model.lazy="draftTitle" />
</template>.number is the one people trust least until they hit it: <input type="number"> looks numeric, but v-model without .number still gives you the string "25", not the number 25. "25" + 1 is "251", not 26 — a bug that only shows up the first time that value is used in arithmetic rather than just displayed back.
A checkbox group binds straight to an array
Binding several checkboxes to one array is built in — no manual push/splice code needed:
<script setup lang="ts">
import { ref } from 'vue'
const interests = ref<string[]>([])
</script>
<template>
<input type="checkbox" value="music" v-model="interests" />
<input type="checkbox" value="sports" v-model="interests" />
</template>Checking a box pushes its value into interests; unchecking it splices that value back out. The array holds exactly the checked values, in the order they were checked — not the order the checkboxes appear in the template, which trips people up the first time they rely on it for anything order-sensitive.
Radio groups and <select> follow the same idea
A radio group bound to the same v-model holds a single selected value, not an array — checking one radio sets the ref to its value, and only one can ever be checked at a time by construction. A <select multiple> bound to an array works like the checkbox group; a plain <select> bound to a ref holds one selected value, same as a radio group.
What interviewers check
Whether .number gets named specifically — "I\'d cast it myself, or use .number" is a common half-answer that misses that the modifier exists precisely so nobody has to remember to cast form input by hand, on every field, every time.
Now practice it
2 quizzes · 1 drillReading this page is the cheap half. These are the exercises that make you use it.
- Form Input BindingsFix a form missing .trim and .number, and replace two hand-rolled booleans with v-model on a shared array.DrillSolve · EasyDrillSolve · Easy
- Options API · Vue FundamentalsForm binding basics sit inside the same Vue Fundamentals set this page draws its examples from.QuizTake · EasyQuizTake · Easy
- Pinia State · Pinia BasicsA form's values are exactly the shape of state a Pinia store often holds — this set connects the two.QuizTake · EasyQuizTake · Easy
Read next
Template Syntax: Interpolation and Bindings
What {{ }} can and cannot render, why every dynamic attribute needs v-bind, and how :class and :style differ from a plain HTML string.
3 min
Computed Properties: Cached, Derived State
A computed only recalculates when a dependency it read actually changes — the caching a plain method call can never give you.
3 min