
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.