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.

Need help integrating this into your project?

Our team of expert developers can help you build your custom application from scratch.

Hire DigitalCodeLabs