JAVASCRIPT
Building a Custom Input with `defineModel` in Vue 3.4+
Learn to create highly customizable form inputs in Vue 3.4+ using `defineModel` for simplified two-way data binding with `v-model`.
<!-- src/components/MyCustomInput.vue -->
<template>
<div class="custom-input-wrapper">
<label v-if="label">{{ label }}</label>
<input
type="text"
:value="model"
@input="event => model = event.target.value"
:placeholder="placeholder"
/>
<p v-if="hint" class="hint-text">{{ hint }}</p>
</div>
</template>
<script setup>
import { defineProps, defineModel } from 'vue';
// Define the primary v-model
const model = defineModel(); // This binds to 'modelValue' prop and 'update:modelValue' event by default
defineProps({
label: String,
placeholder: String,
hint: String,
});
</script>
<style scoped>
.custom-input-wrapper {
display: flex;
flex-direction: column;
margin-bottom: 15px;
}
label {
font-weight: bold;
margin-bottom: 5px;
}
input {
padding: 8px 10px;
border: 1px solid #ccc;
border-radius: 4px;
font-size: 1em;
}
input:focus {
outline: none;
border-color: #007bff;
box-shadow: 0 0 0 0.1rem rgba(0, 123, 255, 0.25);
}
.hint-text {
font-size: 0.85em;
color: #666;
margin-top: 5px;
}
</style>
<!-- src/App.vue (Example usage) -->
<template>
<div id="app">
<MyCustomInput
v-model="searchText"
label="Search Term"
placeholder="Enter your search query"
hint="Type something to see two-way binding"
/>
<p>Current Search: {{ searchText }}</p>
</div>
</template>
<script setup>
import { ref } from 'vue';
import MyCustomInput from './components/MyCustomInput.vue';
const searchText = ref('');
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
How it works: In Vue 3.4+, `defineModel()` simplifies the process of implementing `v-model` on custom components. Previously, this required defining a `modelValue` prop and emitting an `update:modelValue` event. With `defineModel()`, you get a reactive reference that automatically handles both the prop and the event, making two-way data binding with `v-model` much more concise and intuitive. This snippet demonstrates building a custom input component that fully supports `v-model` out of the box.