How to Use v-model with Custom Component in Vue
To use
v-model with a custom Vue component, define a modelValue prop and emit an update:modelValue event when the value changes. This setup enables two-way binding between the parent and the custom component using v-model.Syntax
When using v-model on a custom component, Vue expects the component to:
- Accept a
modelValueprop which holds the current value. - Emit an
update:modelValueevent with the new value when it changes.
This allows the parent to bind data with two-way binding using v-model.
vue
<template> <CustomInput v-model="text" /> </template> <script setup> import CustomInput from './CustomInput.vue' import { ref } from 'vue' const text = ref('') </script>
Example
This example shows a custom input component that works with v-model. The parent binds a text variable to the input. When the user types, the input emits the updated value, and the parent updates automatically.
vue
<!-- CustomInput.vue -->
<template>
<input
:value="modelValue"
@input="$emit('update:modelValue', $event.target.value)"
aria-label="Custom input"
/>
</template>
<script setup>
const props = defineProps(['modelValue'])
</script>
<!-- ParentComponent.vue -->
<template>
<CustomInput v-model="text" />
<p>You typed: {{ text }}</p>
</template>
<script setup>
import { ref } from 'vue'
import CustomInput from './CustomInput.vue'
const text = ref('')
</script>Output
You typed: (shows typed text dynamically)
Common Pitfalls
Common mistakes when using v-model with custom components include:
- Not using the
modelValueprop name, which breaks the binding. - Emitting events with the wrong name (must be
update:modelValue). - Mutating the prop directly inside the component instead of emitting updates.
Always treat props as read-only and emit events to update the value.
vue
<!-- Wrong way: emits 'input' event instead of 'update:modelValue' --> <template> <input :value="modelValue" @input="$emit('input', $event.target.value)" /> </template> <script setup> const props = defineProps(['modelValue']) </script> <!-- Right way: emits 'update:modelValue' event --> <template> <input :value="modelValue" @input="$emit('update:modelValue', $event.target.value)" /> </template> <script setup> const props = defineProps(['modelValue']) </script>
Quick Reference
- Prop name:
modelValue - Event name:
update:modelValue - Usage:
<CustomComponent v-model="data" /> - Inside component: Use
defineProps(['modelValue'])and emitupdate:modelValueon changes.
Key Takeaways
Use the prop name 'modelValue' in your custom component to receive the bound value.
Emit 'update:modelValue' event with the new value to enable two-way binding.
Never mutate props directly; always emit events to update the parent state.
Use
v-model on your custom component to bind data easily.Follow Vue's naming conventions for smooth integration with
v-model.