Reusable Form Components with Vue 3 - read the full article about Vue Js update, Web Development and from Vue Mastery on Qualified.One
- From login and registration screens to checkout pages, forms are arguably the most important and valuable tool for communicating with the end-users of our applications and collecting valuable information from them.
Vue makes it fun and easy to build a wide array of forms, ranging from single-input forms, like a search bar, to very complex schema-driven forms, thanks to its component-driven architecture and reactivity system.
Vue is of course a component-based framework where we can create a bit of code and reuse it throughout our application in a package container called a component.
These components communicate with each other via props and events.
And through these connections, we create a dynamic application.
Forms, in particular, benefit greatly from encapsulating the logic of input elements into components.
As our applications grow, our forms usually grow too.
And having forms that are built without components usually becomes a ticking time bomb.
At some point, you might need to change the look and feel of your elements, or perhaps make them behave differently in relation to their label, or even introduce a new type of validation.
All of these scenarios become exponentially more complex when your inputs in your form are not encapsulated into components.
In this course, we will build a set of components that will handle the most common cases for form inputs in your applications.
They will be highly reusable, but also adaptable to scale for any of your application needs.
While building these components, we will reinforce the fundamental concepts of how components communicate with each other and your form through props, events, listeners, attributes, and so on.
We will go through the best practices on how to capture and submit our forms.
And finally, we will touch up on the basics of accessibility.
With this concept and new tools under your developer tool belt, you will be able to understand and build any range of forms for your own applications.
In order to get the most out of this course, you should have experience with the following topic.
A basic understanding of what v-model is and how it interacts with native input elements.
If you are unfamiliar with it, I recommend that you check our intro to Vue 3 course.
We will incorporate this concept while focusing on how Vue 3 simplifies and empowers form component composition.
Throughout this course, we will be building a set of reusable form components and exploring best practices along the way.
In order to build this, well want a demo form to use as a starting point, which we will break apart into these base components.
Ive prepared one so that we can jump right in.
We have a form that includes a couple of different input elements.
A select element for the category, a few input elements of type text, a radio input and two check boxes.
Everything in this form is v-modeled.
Lets look at the code behind this.
Heres a code for the form that we just saw.
As you can see, it contains the HTML code for all the input elements that we just saw in the browser.
Lets now scroll down to our script section.
Inside the export default, we have our data function.
Inside the return object, we have a categories array that is being used to power the select element.
We also have an event object.
Each of its properties are being bound into one of our elements in the form.
The goal of this lesson is to create a base input component.
Whenever we are building forms in Vue, creating reusable form components for each specific input type will allow us to replicate them, modify them, and extend them.
This also ensures that throughout our form and even throughout our whole application our inputs will be consistent.
Lets dive right in and create our first component.
Were gonna get started by going into the components folder and creating the BaseInput.vue file.
We will also add the template that will hold our code.
Now I will go to the SimpleForm.vue component and copy the code for the first element.
Im gonna copy the label and the input and bring it over to our BaseInput.vue component.
We are going to transform this static code into something more reusable and flexible.
After all, thats the benefit of making components.
In Vue 3, we can have multiple root nodes.
This means we can have the label and the input at root level without needing to wrap them in a single root element like a div, like we have to in Vue 2.
Lets check out the things that we need to do in order to make this component completely reusable and flexible.
First, were going to add a label property.
Then we need to figure out how to allow v-modeling into our component.
Finally, were going to look at how to bind the $attrs object into our component correctly.
The first thing we need to do is to allow our component to receive a label from the parent.
To do this, were going to create a label property.
Lets go ahead and add the script and the export default and the props object.
Well create a label property with the type of string and a default of an empty string.
Now we can use our new label property through interpolation inside our templates label element.
While were at it, were going to delete the v-model directive since were no longer going to be using it inside the component.
Well come back to using v-model later on.
We will also delete type because it will be provided as part of the attributes by the parent.
Remember that we want to keep the component as flexible as possible.
The user of this component may want to make it of type email or password, and the default for input is already of type text if not declared.
Finally, lets bind the placeholder attribute to our label property as well.
This will make sure that both the hint, text inside the input, and the actual label, are coordinated and reactive.
Now that our component has its basic structure and the label, we can move to adding the capability for our component to be v-model ready.
By default in Vue 3, v-model expects a property named modelValue to be on your v-model-capable component.
Lets go ahead and add this new property, and then bind it to the value attribute of our input.
We will add the modelValue property here with the type of string or number and default it to an empty string.
There is a good chance that the parent may try to bind either a text or string like hello to our input, but it may also try to bind a numeric value, like the users age or 30.
We need to be able to allow either to be set.
Lets go ahead and add the value binding and bind it to our new property, modelValue.
Now that we have our modelValue property set and bound to the input attribute of the input element, lets look at the second part of the v-model two-way binding, emitting an event.
All components that are capable of being v-modeled, have to emit an event in order for the parent to be able to catch the updates to that components data.
In Vue 3, by default, all v-model contracts expect for your component to emit an update modelValue event, regardless of what type of input or inputs your component contains.
Lets go ahead and add an input event listener to our input element and emit an update modelValue event whenever an input element occurs.
Lets go ahead and add the input event listener.
Were going to $emit the update modelValue event.
And as a payload, we will pass event target.value.
Adding this input listener to our input element allows us to fire off the required event every time the user types something into the input field.
Notice that were passing the events target value, event.target.value as the payload of the event.
This is the value that the v-model will receive on the parent.
Speaking of the parent, lets go back to our form and use a new BaseInput component, instead of our native elements to test out our code.
We will replace title description and location inputs in our form with our new component.
Lets navigate back to SimpleForm.
We will add our first BaseInput here, and it will replace the title.
So we will bind v-model again to event.title.
Next, we will set the label property equal to title.
Finally, we will add a type of text.
We can now delete the original code.
Remember that label is not an attribute, it is the property that we created in the beginning of this lesson.
Next, lets add another BaseInput for our description.
We will add a v-model binding to event.description.
Next, we will set our label equal to description, and finally, the type equal to text.
We can now delete the original code.
Lets go ahead and do this one more time for our location.
We will create another BaseInput instance.
Then we will v-model it to event.location.
We will set our label property equal to location and our type of equal to text.
We can then, again, delete the original code.
Lets go ahead and look at this in the browser.
At the moment of this recording, the Vue 3 developer tools are still in beta.
Ive gone ahead and outed the output of our v-model bindings here into the form so that we can see it in action.
Im gonna go ahead and write something into our inputs.
Our component seems to be working, but there seems to be a problem with the styles.
If we inspect the component further, it seems that our type attribute is nowhere to be found.
We want to be able to assign attributes like type into the components input when we set them on the instance in the parent.
Lets take a look at how to achieve this.
Before we go into the code, lets check out our to-do list.
Weve added the label property.
Weve made sure that v-modeling works into our component.
Now we will look into how to bind the attrs object correctly.
In Vue, whenever you pass down attributes, classes, and styles from the parent to a child like we are doing with the type in our BaseInput component, Vue will attempt to automatically figure out where inside your template this attribute should be injected.
In components with a single-wrapping element, also known as a single-root components, this behavior is very straightforward.
Vue will simply inject all the attributes, classes, and styles into the root element.
In multi-root components, such as our BaseInput, Vue cannot figure out without our help which one of the nodes or fragments it should inject the attributes to.
So Vue simply gives up and issues a warning.
In the case of our BaseInput component, we want to be able to inject attributes directly into the input, so we have to manually bind the attrs object to it.
Lets go ahead and do that now by binding the attrs into our input element.
Lets go ahead and add a v-bind declaration here.
Inside of this declaration, we will add $attrs.
With this small change, the input elements will now correctly receive the type binding from the parent and our CSS classes will be applied.
Lets check this out in the browser.
Everything is looking a lot better now.
Lets see if it still works.
Everything seems to be working correctly.
(upbeat music) In this lesson, we learned how to create our first component, the BaseInput.
We also learned how to create a component that is v-model ready.
Did you notice that we never actually imported BaseInput in our form component before we used it? I dont want you to worry about that right now.
In lesson four, we will go into detail about the magic that happens behind the scenes in order to accomplish this.
In our next lesson, we will build our next form component, the BaseSelect.
See you there.
Vue Mastery: Reusable Form Components with Vue 3 - Web Development