How to Use Vue 3 v-model Directive in Custom Components

Robin
Updated on October 21, 2022

In Vue 3, the v-model is a directive that is used for creating two-way data binding. Normally, we use this directive to bind any HTML form element with a variable to collect the input value.

But often we need to bind with a form element, that is present in a different component. In this case, you have to use a v-model to custom components.

In this way, you can bind a variable with an HTML element that is inside a child component.

In the latest version of Vue i.e. Vue 3, we have to follow different rules than we used to follow in Vue 2.

In this article, I will show you the best possible way to add the v-model directive to custom components in Vue 3 very easily.

If you are using Vue 2, you can follow our other post on how to add v-model to custom components in Vue2.

How Does v-model Work in Vue 3?

As you know, we use v-model to bind a variable and a form element like input, textarea, and select together so that if you change the value in one place it also changes in another one.

But to implement v-model to custom components, have to know how this directive works in the background.

When we add v-model in an input field, Vue automatically adds two things behind the scene to that input.

  • Vue bind the value attribute of that input field with the variable we provide in v-model.
  • Vue adds the JavaScript input event to that input field so that every time users write or remove something in the input field that event fires.

This is exactly what you have to do if you want to use v-model to custom components in Vue 3.

Best Ways to Use v-model to Custom Components in Vue 3 (Absolute Guide)

Use Vue 3 v-model in Custom Components

To add v-model support to a custom component, there are 3 simple steps:

  • Step 1: Add a modelValue prop to the component as a string.
  • Step 2: Register a update:modelValue event in the component.
  • Step 3: Emit update:modelValue event when the input value changes.

You have to use the same prop and event names. They are case-sensitive. Later, I will show you how you can use different prop and event names with a component.

But before that let's discuss each step in detail with examples. Here I will create a BaseInput.vue component.

          <!-- App.vue component -->

<template>
    <base-input v-model="content"></base-input>
</template>
        

When I use this component inside my App.vue component, I want to use v-model directive. At this moment, this attribute won't do anything.

With the previously discussed 3 steps, you can add the support for this attribute to the BaseInput.vue component.

Step 1: Add modelValue Prop to The Component

SFC (Single File Components) syntax is added in the latest version of Vue 3. Using this syntax, you can write clean and readable code inside your component.

          <!-- BaseInput.vue component -->

<script setup>
const props = defineProps({
    modelValue: String
})
</script>
        

You can define the modelValue prop as a String by calling the defineProps() method. You don't have to import this method. All Vue components have access to it by default.

Step 2: Register update:modelValue Event in The Component

Call the defineEmits() method to register the update:modelValue event in the BaseInput.vue component.

Like defineProps() method, you don't have to import it from Vue. Your component can access this method automatically.

          <!-- BaseInput.vue component -->

<script setup>
const emit = defineEmits(['update:modelValue'])
</script>
        

Pass an array of the event names as strings to this method. It will register those events so that this component can emit them.

Step 3: Emit update:modelValue Event When The Value Changes

After adding the prop and event in our BaseInput.vue component, its time to use them and emit the update:modelValue event when the prop value changes.

          <!-- BaseInput.vue component -->

<template>
    <div>
        <input type="text" :value="modelValue" @input="updateValue" />
    </div>
</template>

<script setup>
const props = defineProps({
    modelValue: String
})

const emit = defineEmits(['update:modelValue'])

const updateValue = (event) => {
    emit('update:modelValue', event.target.value)
}
</script>
        

I am binding the modelValue prop to the value property in my <input> tag. When someone types in the <input> field, the updateValue() method will run.

It will emit the update:modelValue event with the input value. With these 3 steps, we have added support for v-model attributes in our BaseInput.vue component.

Also Read: Improve Performance in Vue 3 Using Lazy Loading and Dynamic Import

Add v-model in Custom Components with setup() Function

If you are using the composition API setup() function in your component, you can follow this method to add v-model support to a custom component.

          <!-- BaseInput.vue component -->

<template>
    <div>
        <h2>Composition API</h2>
        <input type="text" :value="modelValue" @input="updateValue" />
    </div>
</template>

<script>
export default {
    props: {
        modelValue: ''
    },

    setup(props, context) {
        const updateValue = (event) => {
            context.emit('update:modelValue', event.target.value);
        }

        return { updateValue }
    }
}
</script>
        

In composition API, we have to use the same prop name and emit the same event as the options API.

You just have to follow the composition API syntax in your component.

In this component, I have used the setup() function that is required for composition API.

          <!-- App.vue component -->

<template>
    <base-input v-model="content"></base-input>
</template>
        

Now you can use the BaseInput component in any other components and apply the v-model directive to it.

Also Read: Composition API VS Options API in Vue 3 For Beginners

Add v-model to Custom Components with Options API

Even if you don't use Vue 3 composition API, you can follow the same steps to add support for v-model directive in your components.

          <!-- BaseInput.vue component -->

<template>
    <div>
        <h2>Options API</h2>
        <input type="text" :value="modelValue" @input="updateValue" />
    </div>
</template>

<script>
export default {
    props: {
        modelValue: ''
    },
    methods: {
        updateValue(event) {
            this.$emit('update:modelValue', event.target.value);
        }
    }
}
</script>
        

As you can see, it doesn't matter which syntax you are using in your components. You can use the same prop and event names.

Customizing v-model Default Prop and Event Names

As of now, we have used the same prop name as modelValue and the same event name as update:modelValue. But what if you want to use different names?

Now I will show you how you can use a different name for prop and event when you usev-model to custom components.

          <!-- BaseInput.vue component -->

<template>
    <div>
        <h2>Custom name for Prop and Event</h2>
        <input type="text" :value="title" @input="updateTitle" />
    </div>
</template>

<script setup>
const props = defineProps({
    title: String
})

const emit = defineEmits(['update:title'])

const updateTitle = (event) => {
    emit('update:title', event.target.value)
}
</script>
        

In the above example, I have used title as my prop name, which is added to the :value="" attribute.

Now you can emit update:title event whenever a user enters something in the input field. I am using update:title because my prop name is title. If you use another name, you just have to add that name with the prefix update:.

          <!-- App.vue component -->

<template>
    <base-input v-model:title="postTitle"></base-input>
</template>
        

When you apply v-model to that component, you must mention the prop name that you have used in the BaseInput.vue component.

Also Read: watch VS watchEffect in Vue 3 - Must Know Differences

Multiple Vue 3 v-model in a Custom Component

In Vue 2, we were allowed to use v-model only once in a component.

But in Vue 3, we can attach multiple v-model to a component at the same time. This is how you can use multiple v-model to custom components.

          <!-- BaseInput.vue component -->

<template>
    <div>
        <h2>Title</h2>
        <input type="text" :value="title" @input="updateTitle" />
        <h2>Content</h2>
        <input type="text" :value="modelValue" @input="updateContent" />
    </div>
</template>

<script setup>
const props = defineProps({
    title: String,
    modelValue: String
})

const emit = defineEmits(['update:title', 'update:modelValue'])

const updateTitle = (event) => {
    emit('update:title', event.target.value)
}

const updateContent = (event) => {
    emit('update:modelValue', event.target.value)
}
</script>
        

In the above example, I have used a custom prop name and a custom event name for one v-model directive.

For another one, I will use the default names. But you can set custom names for both of them if you want.

All you have to remember is that in your event name, you will add the prop name with the prefix update:.

          <!-- App.vue component -->

<template>
    <base-input v-model="content" v-model:title="postTitle"></base-input>
</template>
        

When you use BaseInput.vue component, you have to mention two v-model directives at the same time.

In this case, you will attach the custom prop name with one v-model. For the default name, you don't need to add anything to it.

Conclusion

I have shown you the best ways to apply the v-model directive to Vue 3 your components. You have learned to do this using options API, composition API, and SFC script setup.

Whatever syntax you follow to create your component, now we will be able to use the v-model to components in Vue 3 projects.

Related Posts