patternjavascriptvueTip
Vue 3 v-model on custom components with defineModel
Viewed 0 times
defineModel stable in Vue 3.4
v-modeldefineModelmodelValuetwo-way bindingcustom componentupdate:modelValue
Problem
Implementing two-way data binding on custom components requires boilerplate: defining a modelValue prop and emitting update:modelValue. Vue 3.4 introduces defineModel() to simplify this.
Solution
Use defineModel() in Vue 3.4+ or the manual pattern for older versions:
// Vue 3.4+ — defineModel (recommended)
<script setup>
const model = defineModel(); // basic
const model = defineModel({ default: '' }); // with default
// Named model for multiple v-models
const title = defineModel('title');
const content = defineModel('content');
</script>
<template>
<input :value="model" @input="model = $event.target.value" />
</template>
// Parent usage:
// <MyInput v-model="text" />
// <MyForm v-model:title="title" v-model:content="body" />
// Manual pattern (Vue 3.0–3.3)
<script setup>
const props = defineProps({ modelValue: String });
const emit = defineEmits(['update:modelValue']);
</script>
<template>
<input
:value="props.modelValue"
@input="emit('update:modelValue', $event.target.value)"
/>
</template>
// Vue 3.4+ — defineModel (recommended)
<script setup>
const model = defineModel(); // basic
const model = defineModel({ default: '' }); // with default
// Named model for multiple v-models
const title = defineModel('title');
const content = defineModel('content');
</script>
<template>
<input :value="model" @input="model = $event.target.value" />
</template>
// Parent usage:
// <MyInput v-model="text" />
// <MyForm v-model:title="title" v-model:content="body" />
// Manual pattern (Vue 3.0–3.3)
<script setup>
const props = defineProps({ modelValue: String });
const emit = defineEmits(['update:modelValue']);
</script>
<template>
<input
:value="props.modelValue"
@input="emit('update:modelValue', $event.target.value)"
/>
</template>
Why
v-model on a component is syntactic sugar for :modelValue + @update:modelValue. defineModel() (Vue 3.4+) generates the prop and emit automatically and returns a writable computed ref — eliminating the boilerplate. The underlying mechanism is the same.
Gotchas
- defineModel is a compiler macro — available in <script setup> only
- Multiple v-models require named models: v-model:title, v-model:content
- v-model modifiers (.trim, .number) work with defineModel's second argument
- For Vue < 3.4, defineModel is available as a plugin via vue-macros
Code Snippets
defineModel with custom modifier handling
<script setup>
// With modifier support
const [model, modifiers] = defineModel({
set(value) {
if (modifiers.trim) return value.trim();
return value;
}
});
</script>Context
When building reusable input components in Vue 3 that support v-model
Revisions (0)
No revisions yet.