JAVASCRIPT
Build a Custom Input Component with v-model in Vue 3
Learn to create a custom reusable input component in Vue 3 that fully supports `v-model` for two-way data binding, enhancing form development and component reusability.
<!-- MyCustomInput.vue -->
<template>
<label :for="id">{{ label }}</label>
<input
:id="id"
:type="type"
:value="modelValue"
@input="onInput"
class="custom-input"
/>
</template>
<script setup>
import { computed } from 'vue';
const props = defineProps({
modelValue: { // The default prop for v-model
type: [String, Number],
default: ''
},
label: {
type: String,
default: 'Input Label'
},
type: {
type: String,
default: 'text'
}
});
const emit = defineEmits(['update:modelValue']); // The default event for v-model
const id = computed(() => `custom-input-${Math.random().toString(36).substr(2, 9)}`);
const onInput = (event) => {
emit('update:modelValue', event.target.value);
};
</script>
<style scoped>
.custom-input {
padding: 8px 12px;
border: 1px solid #ccc;
border-radius: 4px;
font-size: 16px;
width: 100%;
box-sizing: border-box;
}
.custom-input:focus {
outline: none;
border-color: #007bff;
box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.25);
}
label {
display: block;
margin-bottom: 5px;
font-weight: bold;
}
</style>
<!-- Usage Example: -->
<!-- <template>
<div>
<MyCustomInput v-model="userName" label="Your Name" />
<p>User Name: {{ userName }}</p>
<MyCustomInput v-model="userAge" label="Your Age" type="number" />
<p>User Age: {{ userAge }}</p>
</div>
</template>
<script setup>
import { ref } from 'vue';
import MyCustomInput from './MyCustomInput.vue'; // Assuming MyCustomInput is this component
const userName = ref('John Doe');
const userAge = ref(30);
</script> -->
How it works: This snippet demonstrates how to create a custom input component in Vue 3 that fully supports the `v-model` directive. For `v-model` to work, a custom component must accept a `modelValue` prop (which holds the current value) and emit an `update:modelValue` event whenever its internal value changes. This pattern allows the custom input to behave just like native HTML inputs when used with `v-model`, enabling seamless two-way data binding. The component also includes `label` and `type` props for flexibility and basic styling for reusability.