How to make reusable form input element in Vue.js 2.6 and Vue.js 3.0
Some months ago I’ve attended the Vue.js Workshop held by Chris Fritz. In this workshop, he showed us a Vue.js component wrapping technique which is called transparent wrapper component.
With this technique, you can give to native components like input, selects and other inputs superpowers. We will go over every part of this pattern and understand how it’s done.
Let’s start with a simple input component first.
Basic Input
In the beginning, we will create <CustomInput/> component
The first problem is that we want to make v-model work on these components so everyone can use it with the same syntax we already know. We know that v-model is just a shorthand for binding a value and emitting an event.
I see people adding custom events for each native event to the component, but we can do the same by binding the parent event listeners to our child component with v-on="$listeners".
How to disable automatic attribute inheritance in Vue 2.x
By default, all HTML attributes of the element, which are not declared as props are automatically inherited by the first wrapping element in your component. Only :styles and :classes are converted to props automatically and they are not passed down by attribute inheritance. This behaviour is a little bit opaque and many people don’t understand it at first.
So if you are using input element as the only element in your custom input component everything will work just fine. But if we start to introduce some div or label as a wrapper for our input, automatic attribute inheritance will add a placeholder to the div element and not to the desired input element.
// CustomInput.vue
<template>
<div>
<!-- placeholder is not longer on the `input` element -->
<input
type="text"
v-on="$listeners"
:value="value"
@input="$emit('update', $event.target.value)">
</div>
</template>
<script>
export default {
props: ["value"],
model: {
prop: "value",
event: "update"
}
};
</script>
// App.vue
<CustomInput
placeholder="Your Name"
@keydown.enter="search"
v-model="name"
label="Awesome Label"
/>
We can fix this by disabling the automatic attribute inheritance and add it to the element where it belongs to.
Our basic input should be able to handle the following types: text, password, email, number, url, tel, search and color. In the next step, we will create a prop validation.
Thank you for this article. It’s a wonderful reference!
What’s the model attribute for? Why is it present?
You can control how the v-model behaves. What property it will receive and what even it will emit
Explained very well. Thanks for this article 👍
Fantastic article! Do you have an example for ?
Sure you can read it now on the official Vue3 documentation