JAVASCRIPT
Building Custom `v-model` Components with `defineModel`
Learn how to easily implement `v-model` functionality on custom Vue 3 components using the new `defineModel` macro (Vue 3.4+), simplifying two-way data binding.
// MyCustomInput.vue (Vue 3.4+ required for defineModel)
<template>
<label>{{ label }}:
<input
type="text"
:value="model"
@input="model = $event.target.value"
class="custom-input"
/>
</label>
</template>
<script setup>
import { defineProps } from 'vue';
const props = defineProps({
label: {
type: String,
default: 'Input'
}
});
// Define a model for two-way binding. 'model' is the default name.
// You can also name it: const myValue = defineModel('myValue');
const model = defineModel();
// Older approach (pre Vue 3.4):
// const props = defineProps(['modelValue']);
// const emit = defineEmits(['update:modelValue']);
// const localValue = computed({
// get: () => props.modelValue,
// set: (value) => emit('update:modelValue', value),
// });
</script>
<style scoped>
.custom-input {
border: 1px solid #ccc;
padding: 8px;
border-radius: 4px;
}
</style>
// --- In a parent component (e.g., App.vue) ---
<template>
<div>
<h1>Custom Input Example</h1>
<MyCustomInput label="Your Name" v-model="userName" />
<p>Current Name: {{ userName }}</p>
</div>
</template>
<script setup>
import { ref } from 'vue';
import MyCustomInput from './MyCustomInput.vue';
const userName = ref('John Doe');
</script>
How it works: The `defineModel` macro (introduced in Vue 3.4) simplifies creating components that support `v-model` for two-way data binding. When `v-model` is used on a component, it typically binds to the `modelValue` prop and listens for the `update:modelValue` event. `defineModel` abstracts this, automatically defining the `modelValue` prop and providing a `ref`-like value that can be directly used in the template and automatically emits the `update` event when its value changes. This makes building reusable form inputs much more straightforward.