JAVASCRIPT

Implementing `v-model` on Custom Vue 3 Components

Learn to make your custom Vue 3 components compatible with `v-model`, enabling two-way data binding for cleaner and more intuitive form input abstraction.

<!-- App.vue -->
<template>
  <div>
    <p>Parent Value: {{ myValue }}</p>
    <CustomInput v-model="myValue" placeholder="Enter text" />
    <CustomInput v-model:checked="isChecked" type="checkbox" label="Check me" />
    <p>Is Checked: {{ isChecked }}</p>
  </div>
</template>

<script setup>
import { ref } from 'vue';
import CustomInput from './components/CustomInput.vue';

const myValue = ref('Hello Vue!');
const isChecked = ref(false);
</script>

<!-- components/CustomInput.vue -->
<template>
  <label v-if="type === 'checkbox'">
    <input
      :type="type"
      :checked="checked"
      @change="$emit('update:checked', $event.target.checked)"
    />
    {{ label }}
  </label>
  <input
    v-else
    :type="type"
    :value="modelValue"
    @input="$emit('update:modelValue', $event.target.value)"
    :placeholder="placeholder"
  />
</template>

<script setup>
import { defineProps, defineEmits } from 'vue';

const props = defineProps({
  modelValue: { // Default prop name for v-model
    type: String,
    default: ''
  },
  checked: { // Prop name for v-model:checked
    type: Boolean,
    default: false
  },
  type: {
    type: String,
    default: 'text'
  },
  placeholder: {
    type: String,
    default: ''
  },
  label: {
    type: String,
    default: ''
  }
});

const emit = defineEmits(['update:modelValue', 'update:checked']); // Default event name for v-model
</script>

<style scoped>
input {
  padding: 8px;
  border: 1px solid #ccc;
  border-radius: 4px;
  margin-bottom: 10px;
}
label {
  display: block;
  margin-bottom: 10px;
}
</style>
How it works: This snippet demonstrates how to implement `v-model` on custom Vue 3 components, allowing for two-way data binding. For a standard input, the component accepts a `modelValue` prop and emits an `update:modelValue` event. For multiple `v-model` bindings (e.g., `v-model:checked`), custom prop and event names are used (e.g., `checked` prop and `update:checked` event). This pattern enables you to encapsulate complex input logic within reusable components while maintaining a clean and familiar API for parent components.

Need help integrating this into your project?

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

Hire DigitalCodeLabs