0
0
VueHow-ToBeginner · 3 min read

How to Use v-model on Vue Component: Simple Guide

To use v-model on a Vue component, define a modelValue prop and emit an update:modelValue event from the child component. Then, bind v-model on the component in the parent to enable two-way data binding.
📐

Syntax

Use v-model on a custom component by binding it to a prop named modelValue and emitting update:modelValue events when the value changes.

This pattern allows the parent to pass data down and listen for changes from the child.

vue
<template>
  <CustomInput v-model="text" />
</template>

<script setup>
import { ref } from 'vue'
import CustomInput from './CustomInput.vue'

const text = ref('')
</script>
💻

Example

This example shows a parent component using v-model with a child input component. The child receives modelValue as a prop and emits update:modelValue when the input changes.

vue
<!-- CustomInput.vue -->
<template>
  <input
    :value="modelValue"
    @input="$emit('update:modelValue', $event.target.value)"
    aria-label="Custom input"
  />
</template>

<script setup>
import { defineProps, defineEmits } from 'vue'

const props = defineProps({
  modelValue: String
})

const emit = defineEmits(['update: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('Hello')
</script>
Output
You typed: Hello (updates live as you type)
⚠️

Common Pitfalls

  • Not using modelValue as the prop name breaks v-model binding.
  • Forgetting to emit update:modelValue event means the parent won't know about changes.
  • Using a different event name or prop requires manual v-model customization.
vue
<!-- Wrong: prop named 'value' and event 'input' (legacy) -->
<template>
  <input :value="value" @input="$emit('input', $event.target.value)" />
</template>

<script setup>
const props = defineProps({ value: String })
const emit = defineEmits(['input'])
</script>

<!-- Right: use 'modelValue' and 'update:modelValue' -->
<template>
  <input :value="modelValue" @input="$emit('update:modelValue', $event.target.value)" />
</template>

<script setup>
const props = defineProps({ modelValue: String })
const emit = defineEmits(['update:modelValue'])
</script>
📊

Quick Reference

v-model on component:

  • Prop name: modelValue
  • Event name: update:modelValue
  • Use v-model on component tag in parent
  • Emit update:modelValue with new value from child
ConceptName/Usage
Prop for valuemodelValue
Event to emitupdate:modelValue
Parent usage
Child emits$emit('update:modelValue', newValue)

Key Takeaways

Always use 'modelValue' prop and 'update:modelValue' event for v-model on components.
Emit 'update:modelValue' from child to update parent data reactively.
Bind v-model on the component tag in the parent to enable two-way binding.
Avoid legacy prop/event names like 'value' and 'input' for new Vue 3 components.
Use aria-labels and semantic HTML for accessibility in custom inputs.