Vue handles form inputs cleanly through the v-model directive. It creates two-way data binding between HTML form controls and your reactive state in <script setup>.
When a user types into an input or selects an option, v-model updates your reactive variable right away. When your script updates that variable, the input updates to match.
flowchart LR
Input["Form Control Input"] <-->|v-model| State["Reactive Ref or Object"]
v-model Binds Different Controlsvalue property and listens to input events.true or false value.value of the selected radio option.<option> value or array of values when multiple is set.You can also add .trim, .number, or .lazy modifiers directly onto v-model to clean user input automatically.
<script setup>
import { reactive, ref } from 'vue';
const formData = reactive({
username: '',
age: 25,
bio: '',
newsletter: false,
frameworks: ['vue'],
experience: 'intermediate'
});
const savedPayload = ref('');
function submitForm() {
savedPayload.value = JSON.stringify(formData, null, 2);
}
</script>
<template>
<form @submit.prevent="submitForm" class="form-card">
<label>
Username:
<input type="text" v-model.trim="formData.username" required />
</label>
<label>
Age:
<input type="number" v-model.number="formData.age" />
</label>
<label>
Bio:
<textarea v-model.lazy="formData.bio"></textarea>
</label>
<fieldset>
<legend>Favorite Frameworks</legend>
<label><input type="checkbox" value="vue" v-model="formData.frameworks" /> Vue</label>
<label><input type="checkbox" value="react" v-model="formData.frameworks" /> React</label>
</fieldset>
<label>
<input type="checkbox" v-model="formData.newsletter" /> Subscribe to updates
</label>
<button type="submit">Save Profile</button>
<pre v-if="savedPayload">{{ savedPayload }}</pre>
</form>
</template>
null: Multiple checkboxes need an array (such as []). If the bound property starts as null or false, Vue treats it as a single boolean checkbox instead.value Attribute Alongside v-model: On text inputs and textareas, v-model ignores hardcoded value or checked attributes. Always set initial values inside <script setup>..number on Numeric Inputs: HTML <input type="number"> still emits string values by default. Add v-model.number when you need a real JavaScript number..lazy modifier do on v-model?By default, v-model updates state on every keystroke (input event). Adding v-model.lazy delays the update until the change event, such as when the input loses focus.
v-model on custom Vue components?Yes. In Vue 3, v-model on a child component uses defineModel() in Vue 3.4+ or binds a modelValue prop with an update:modelValue event.
v-model work during IME composition for non-Latin keyboards?No, v-model pauses updates during IME composition (such as Chinese, Japanese, or Korean input) until composition finishes so half-typed characters do not flicker.
Sign in to track your learning journey, earn industry-recognized certificates, and join our elite developer community.
Quick Access With