Vue has always been known for its elegant approach to building user interfaces, and one of the features that makes Vue feel so natural is v-model. In Vue 3, this directive becomes even more powerful, flexible, and developer-friendly.
Whether you’re just getting started or looking to modernize your Vue codebase, this guide will walk you through everything you need to know about using v-model in Vue 3 — from basic input binding to fully customizable component models.
🎯 What Is v-model?
v-model is Vue’s syntax sugar for creating two-way binding between a variable in your component and an input element or child component.
Whenever the input changes, your data updates.
Whenever your data updates, the UI reacts.
Simple, reactive, automatic.
✅ Basic Usage: v-model on Native Inputs
html
<input v-model="username" placeholder="Enter your name" />
js
import { ref } from "vue";
const username = ref("");
Here’s what happens behind the scenes:
- Vue binds the value of
usernameto the input - Vue listens for
inputevents and updates the ref
No events, no boilerplate — just clean code.
🎨 Using v-model on Custom Components
Vue 3 introduced a much-improved pattern for v-model in custom components.
Now, instead of manually declaring props and emit, you can use a single line:
const modelValue = defineModel();
This gives your component:
- A reactive
modelValuevariable - Automatic type inference
- Automatic
update:modelValueevent emission
🧩 Example: Building a Custom Input Component
Child Component: CustomInput.vue
<script setup>
const modelValue = defineModel();
</script>
<template>
<input
class="custom-input"
:value="modelValue"
@input="modelValue = $event.target.value"
/>
</template>
🏠 Parent Usage
<template>
<CustomInput v-model="name" />
<p>Your name: {{ name }}</p>
</template>
<script setup>
import { ref } from "vue";
import CustomInput from "./CustomInput.vue";
const name = ref("");
</script>
Vue automatically links the parent’s name with the child component’s model.
💡 Bonus: Multiple v-model Bindings
Vue 3 also supports multiple models:
<MyRange
v-model:start="min"
v-model:end="max"
/>
Inside the component:
const start = defineModel('start')
const end = defineModel('end')
This makes custom form components far more expressive and maintainable.
📌 Best Practices When Using v-model
- Use
defineModel()for clean, modern components - Keep validation inside the component (local first, emit valid data)
- Use multiple models for sliders, ranges, or complex inputs
- Always initialize your refs with default values
🏁 Conclusion
Vue 3’s updated v-model system is a big step forward in simplicity and power. With cleaner APIs like defineModel(), building reusable, maintainable form components becomes easier than ever.
If you’re starting a new project or modernizing an existing one, adopting the Vue 3 v-model patterns will save time, reduce bugs, and make your code far more elegant.