Two-way data binding is key to creating dynamic apps. Vue.js makes it easy to handle two-way model binding using the v-model directive. In Vue 3.4 the defineModel macro takes this further. It gives you more type safety and cleans up your code.
v-model provides two-way data binding. What does that mean? Changes in the UI update the data, and changes in the data update the UI. v-model is actually shorthand. It combines passing a prop and emitting an event. This helps keep your components in sync.
Before defineModel, v-model used props and $emit. This involved more code. You had to define a prop and emit an update event. This approach worked, but was a bit clunky. It had issues, like more code and potential type errors.
Basic usage:
MyForm.vue
<script setup>
const nameModel = defineModel();
</script>
<template>
<p>
<label>Name</label>
<input type="text" v-model="nameModel" />
</p>
</template>
Declaring a model simply by calling the defineModel() macro, and then passing it to the v-model directive. Now in parent component you can use v-model as well with the child component:
App.vue
<script setup>
...
const data = ref('');
</script>
<template>
<MyForm v-model="data" />
</template>
Now the data is synced in parent and child component. As we know previously to implement this without defineModel() we have to pass a prop and emit an event like so:
MyForm.vue
<script setup>
const props = defineProps(['modelValue']);
const emit = defineEmits(['update:modelValue']);
</script>
<template>
<input
type="text"
:value="props.modelValue"
@input="emit('update:modelValue', ($event.target as HTMLInputElement).value)"
/>
</template>
This approach is working, however you have to write more code and makes the code base more complicated especially if you want to handle multiple v-model in the same component.
defineModel automatically creates the prop and event for v-model. No more manual work! It reduces the amount of code needed. The syntax is straightforward.
Multiple v-model On The Same Component
With defineModel() macro we can handle multiple v-model on the same child component by specifying an argument to v-model i.e “v-model:argument“:
App.vue
<script setup>
...
const name = ref('');
const email = ref('');
</script>
<template>
<MyForm v-model="name" v-model:email="email" />
</template>
In the child component specify the argument name to defineModel() as the first parameter:
MyForm.vue
<script setup>
const nameModel = defineModel();
const emailModel = defineModel('email'); // defineModel with argument
</script>
<template>
<p>
<label>Name</label>
<input type="text" v-model="nameModel" />
</p>
<p>
<label>Email</label>
<input type="email" v-model="emailModel" />
</p>
</template>
Each property passed with v-model to the child component is synced with the parent as usual. This way we can create complex forms with little code.


