v-model and Two-Way Binding
v-model creates two-way binding between a form input and a reactive variable. When the user types, the variable updates. When the variable changes programmatically, the input reflects the new value.
v-model on native inputs
Section titled “v-model on native inputs”<script setup lang="ts">import { ref } from 'vue'
const name = ref('')const birthYear = ref<number | ''>('')const isDeceased = ref(false)const relationship = ref('parent')</script>
<template> <!-- Text input --> <input v-model="name" type="text" placeholder="Full name" /> <p>Name: {{ name }}</p>
<!-- Number input --> <input v-model="birthYear" type="number" />
<!-- Checkbox --> <input v-model="isDeceased" type="checkbox" /> <label>Deceased</label>
<!-- Select --> <select v-model="relationship"> <option value="parent">Parent</option> <option value="child">Child</option> <option value="spouse">Spouse</option> </select></template>v-model is shorthand for binding the value and listening to the input event simultaneously:
<!-- These two are equivalent --><input v-model="name" /><input :value="name" @input="name = $event.target.value" />v-model modifiers
Section titled “v-model modifiers”Strips leading/trailing whitespace automatically:
<input v-model.trim="name" />.number
Section titled “.number”Converts the input value to a number:
<input v-model.number="birthYear" type="number" />Updates on change instead of input (syncs after the user leaves the field):
<input v-model.lazy="bio" />v-model on custom components with defineModel
Section titled “v-model on custom components with defineModel”Vue 3.4+ introduced defineModel — a macro that creates a two-way binding prop for custom components:
<script setup lang="ts">const model = defineModel<string>()</script>
<template> <input :value="model" @input="model = $event.target.value" /></template>The parent uses it exactly like a native input:
<AppInput v-model="personName" />In FamilyTree
Section titled “In FamilyTree”PersonForm.vue uses v-model for every field in the add/edit form:
<input id="pf-name" v-model="name" type="text" placeholder="Full name" required /><input id="pf-birth" v-model="birthYear" type="number" placeholder="e.g. 1952" /><textarea id="pf-bio" v-model="bio" placeholder="A few notes (optional)" />Each field is bound to a local ref. On submit, the refs are collected into a PersonFormData object and emitted to the parent.
Exercise
Section titled “Exercise”- Create a simple person form with
v-modelbindings for name, birth year, and a bio textarea. - Display the current values live below the form as you type.
- Add a “Clear” button that resets all fields to empty strings.
- Add
.trimto the name input and verify that whitespace is stripped automatically.
v-model="ref"creates two-way binding between an input and a reactive variable.- Works on text inputs, number inputs, checkboxes, selects, and textareas.
- Modifiers:
.trim,.number,.lazy. - On custom components, use
defineModel()to create a two-way bindable prop. v-modelis shorthand for:value+@input— understanding the longhand helps when debugging.