Form Input Bindings with v-model
Two-way binding for form inputs, how v-model works across different input types, and what it expands to under the hood.
阅读需 2 分钟
Binding a form input's value with :value only goes one direction: the input shows your state, but typing into it doesn't update that state back. You'd need to pair it with an @input listener that reads event.target.value and writes it back yourself. v-model does both directions in one directive.
<script setup>
import { ref } from "vue";
const searchTerm = ref("");
</script>
<template>
<input v-model="searchTerm" placeholder="Search..." />
<p>You typed: {{ searchTerm }}</p>
</template>Typing in the input updates searchTerm, and changing searchTerm elsewhere in your code updates the input's displayed value — genuinely two-way.
What it expands to
v-model is shorthand. On a text input, it's roughly equivalent to:
<input :value="searchTerm" @input="searchTerm = $event.target.value" />Knowing this expansion matters because v-model isn't one fixed behavior — it adapts based on the element it's used on, using whichever event and property make sense for that element (value/input for text inputs, checked/change for checkboxes, and so on). You're not memorizing unrelated magic; you're memorizing one consistent pattern applied per element type.
Different input types
<script setup>
import { ref } from "vue";
const agreedToTerms = ref(false);
const selectedColor = ref("blue");
const bio = ref("");
</script>
<template>
<label><input type="checkbox" v-model="agreedToTerms" /> I agree</label>
<select v-model="selectedColor">
<option value="red">Red</option>
<option value="blue">Blue</option>
<option value="green">Green</option>
</select>
<textarea v-model="bio" placeholder="Short bio"></textarea>
</template>A checkbox's v-model binds to a boolean; a <select>'s binds to the selected option's value; a <textarea>'s binds to its text, same as a text input. You use the same directive everywhere and let Vue handle the type-specific plumbing.
Modifiers
Like event listeners, v-model supports modifiers for common adjustments:
<template>
<input v-model.trim="username" />
<input v-model.number="age" type="number" />
<input v-model.lazy="query" />
</template>.trimstrips leading/trailing whitespace automatically..numberconverts the typed string to a number — otherwise, even atype="number"input'sv-modelvalue is a string unless you cast it..lazysyncs on thechangeevent (typically, on blur) instead of on every keystroke — useful when you don't need to react to every character typed, and don't want a bound computed value or watcher re-running that often.
Using v-model on your own components
v-model isn't limited to native inputs — you can make your own components support it too, which the props and custom-events lessons later in this course build directly on top of.