How to Use Vue 3 v-model Attribute with Custom Components

Robin
Updated on November 9, 2023

You can use v-model attribute with any of your components in Vue 3 as you use it with input elements. It will help you to create two-way data binding between components.

If you need to bind with a form element, that is present in a different component, 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.

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

What Are We Going to Build?

We will create a BaseInput.vue component where we will have a <input> element. I want to bind the value of this input field with a variable from another component.

This is the complete code for the BaseInput.vue component:

          <!-- 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>
        

Using the BaseInput.vue component inside the App.vue component.

          <!-- App.vue component -->

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

Here I am using v-model attribute with the BaseInput.vue component to bind the content variable that is present inside the App.vue component.

Now if you change the value of the content variable, it will also update the <input> field inside the BaseInput.vue component.

And if you type something in the <input> field, it will automatically update the content variable.


How Does v-model Work in Vue 3?

Before implementing v-model to custom components, you have to know how this attribute works in the background.

When we add v-model in an input field, Vue automatically adds two things.

  • 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 your components in Vue 3.

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

Adding Vue 3 v-model Attribute 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: Define modelValue Prop in 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 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


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 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