Adding v-model Support to Custom Vue.js Components

September 10, 2019


Almost everyone who has worked with Vue.js for few hours knows how two-way data-binding works in form elements. Below snippet shows a very basic example of this data-binding. We have used v-model directive to bind message from app state to the input form element. If you change the input, the DOM (anywhere message is used) will update itself without any explicit code written.

See the Pen pozLPjo by Mustafa Ehsan (@mustafaaloko) on CodePen.

How it works under the hood?

Any component or element which supports v-model out of the box adheres to this contract: accept a prop named value and emit an input event to trigger a data change. Basically, <input v-model="message" /> is a shorthand for writing <input :value="message" @input="message = $ />". Below code achieves the same result as in the first example without using v-model.

See the Pen Vue.js Data-Binding Example without v-model by Mustafa Ehsan (@mustafaaloko) on CodePen.

How to add v-model support in custom components?

Now let’s see how we can add this support in our custom components neatly and without extra or useless code. The idea is that how we can allow our child components to modify its parent component’s state.

In our custom component, all we need to do is accept a value prop and emit an input event on a value change that we want to notify child component’s parent about. Any value which will be passed as the emitted event argument will be passed to parent component to maintain its state.

In the below example, we are creating a custom component named text-input which is a re-usable custom input component we may wanna use for our project. To make sure that it operates same as HTML’s native input element, we will add v-model support as below:

See the Pen Custom Vue.js Component with v-model Support by Mustafa Ehsan (@mustafaaloko) on CodePen.

As shown in the above example, we are calling onInputChange on the input element’s value change which in turn emits the event that we discussed above. That’s it, now you can see that our custom element (<text-input v-model="message" />) supports the v-model directive same as our plain input elements.


Comments powered by Disqus