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

