JAVASCRIPT

Creating Custom Two-Way Bindings with `v-model` on Vue 3 Components

Implement custom `v-model` directives on your Vue 3 components to enable powerful two-way data binding, simplifying state management for reusable UI elements.

// components/CustomInput.vue
<template>
  <input
    :value="modelValue"
    @input="$emit('update:modelValue', $event.target.value)"
    type="text"
    class="custom-input"
    placeholder="Enter text..."
  />
</template>

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

defineProps({
  modelValue: {
    type: String,
    default: '',
  },
});

defineEmits(['update:modelValue']);
</script>

<style scoped>
.custom-input {
  padding: 8px 12px;
  border: 1px solid #ccc;
  border-radius: 4px;
  font-size: 1rem;
  width: 100%;
  max-width: 300px;
}
</style>

<!-- App.vue (example usage) -->
<template>
  <div>
    <h1>Custom Input Example</h1>
    <CustomInput v-model="message" />
    <p>Message: {{ message }}</p>

    <hr>

    <h2>Multiple v-model example (Vue 3.2+)</h2>
    <CustomCheckbox v-model:checked="isChecked" v-model:label="checkboxLabel" />
    <p>Checkbox State: {{ isChecked ? 'Checked' : 'Unchecked' }}</p>
    <p>Checkbox Label: {{ checkboxLabel }}</p>
  </div>
</template>

<script setup>
import { ref } from 'vue';
import CustomInput from './components/CustomInput.vue';
// For the multiple v-model example:
import CustomCheckbox from './components/CustomCheckbox.vue';

const message = ref('Hello Vue!');
const isChecked = ref(true);
const checkboxLabel = ref('Agree to terms');
</script>

<!-- components/CustomCheckbox.vue (for multiple v-model example) -->
<template>
  <div>
    <input
      type="checkbox"
      :checked="checked"
      @change="$emit('update:checked', $event.target.checked)"
      id="custom-checkbox"
    />
    <label for="custom-checkbox" @click="$emit('update:label', prompt('Change label:', label) || label)">
      {{ label }}
    </label>
  </div>
</template>

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

defineProps({
  checked: {
    type: Boolean,
    default: false,
  },
  label: {
    type: String,
    default: 'Default Checkbox',
  },
});

defineEmits(['update:checked', 'update:label']);
</script>
How it works: This snippet illustrates how to implement custom `v-model` functionality on your own Vue 3 components. By accepting a `modelValue` prop and emitting an `update:modelValue` event, you enable two-way data binding, similar to native form inputs. The example also briefly touches on Vue 3.2+'s ability to define multiple `v-model` bindings with specific argument names, enhancing flexibility for complex components.

Need help integrating this into your project?

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

Hire DigitalCodeLabs