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.

Need help integrating this into your project?

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

Hire DigitalCodeLabs