defineModel
is a compiler macro that allows you to declare and mutate v-model
props as the same as a normal variable.
Example without defineModel
Let's take a look at a simple example that uses v-model
. We have a Parent.vue
component that passes a counter ref to a Child.vue
component:
<script setup lang="ts">
import { ref } from 'vue'
import Child from './components/Child.vue'
const state = ref({ count: 0 })
</script>
<template>
<div>
<span>Parent state: {{ state }}</span>
<Child v-model="state.count" />
</div>
</template>
Let's take a look at the implementation of the child component:
<script setup lang="ts">
import { ref } from 'vue'
const props = defineProps<{ modelValue: number }>()
const emit = defineEmits<{
(e: 'update:modelValue', value: number): void
}>()
const onClick = () => {
props.modelValue += 1
emit('update:modelValue', props.modelValue)
}
</script>
<template>
<div>
<span>Child state: {{ modelValue }}</span>
<button @click="onClick">Increment child state</button>
</div>
</template>
As Child.vue
receives the v-model
you need to declare a prop called modelValue
which receives the v-model
value. Additionally, you need to declare an emit called update:modelValue
that is used to update the parent that the modelValue
has been updated.
As props are readonly and you should not mutate them, you cannot update modelValue
and will receive the following warning:
I wrote a tip about this topic and how you can solve this warning. defineModel
provides a nice solution to this problem, so let's take a look at it.
Example with defineModel
defineModel
available since Vue 3.3.0-alpha.9We can simplify our child component by using defineModels
:
<script setup lang="ts">
const { modelValue, count } = defineModels<{
modelValue: number
}>()
const onClick = () => {
modelValue.value += 1
}
</script>
<template>
<div class="container">
<span>Child with defineModels state: {{ modelValue }}</span>
<button @click="onClick">Increment child state</button>
</div>
</template>
The defineModels
compiler macro will declare a prop with the same name and a corresponding update:propName
event when it is compiled.
By updating the modelValue
ref, the corresponding update:propName
event is automatically emitted.
Try it yourself in the following StackBlitz project:
If you liked this Vue tip, follow me on BlueSky to get notified about new tips, blog posts, and more. Alternatively (or additionally), you can subscribe to my weekly Vue & Nuxt newsletter :
Nuxt Tip: Use Nuxt Layers to Share Components, Utils, and Configuration Between Your Apps
Vue Tip: Optimize Performance Using shallowRef