Form Association and Web Components – Today
source link: https://yonatankra.com/form-association-and-web-components-today/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Form Association and Web Components – Today
Recently I’ve joined a team that’s creating a UI library using web components. This is great – but it has its challenges. One of these challenges is form association behind Shadow DOM.
When we create a form, we expect the following from input elements:
- Add the input element’s value to submission if it has a name property
- Enable validation is set (required/pattern/min/max/length/custom)
We also expect buttons of type submit and reset to work out of the box and actually validate and submit and reset respectively.
As shown in various other articles (Arthur Evans on web.dev, Paul H. H. Hansen) – when the input field is hiding behind a shadow DOM (as in many web component based UI components libraries), the above features just wouldn’t work.
The examples in this article are based on a simple webpack project. The project setup is described in details in former articles. If you want to play with the code, simply clone the repo and checkout the
form-association-demo
branch.
A Native Form
Let’s look at an example of how it works without Shadow DOM.
Example 1: A simple form with two fields and a submit button. The two fields are required and the email field validates for a valid email address. The onsubmit is set to
return false
in order to prevent a page refresh on submit. When submitting the form, the form’s data shows in theForm Output
section.
In Example 1, when we click the submit button, we see that the form invalidates and does not submit because one of the fields is required.
Filling all of the fields and clicking the submit button actually submits the form, as can be seen from the output of the submit event.
The code is very simple and can be seen here:
You can view the whole branch here: https://github.com/YonatanKra/web-components-ui-elements/tree/simple-form
A Shadow Form
Our form is not so impressive UX-wise. Our awesome designers have decided we should go with a material look to our form.
Because our company has lots of apps, each built with a different technology (vue, angular, react, etc.), we are going to use the “use everywhere” technology: Web Components.
We have decided to pick a project with a very promising name: Material Web Components.
Adding the Button
Let’s start with something simple. We’d like our button to look better.
That’s pretty simple:
- yarn add @material/mwc-button
- In the
index.js
file we addimport @material/mwc-button
- In the
demo.html
file we replace thebutton
tag withmwc-button
Click here to view the git diff.
The result is this:
Example 2: The same form from Example 1 with the
mwc-button
. You can try to click the button – and even though its type issubmit
nothing happens.
Now our app is broken – the form doesn’t submit if we click the button. The same would apply to a reset button as well as to a button that is explicitly attached to a form (by adding form="simple-form"
attribute to the button).
Supporting Button Types
In order to support form submission and reset, we’d need to change our web component a bit.
We will create a new component that extends the mwc-button
and add the following:
- Handle button click according to the button’s type (submit/reset)
- Handle a
form
attribute to allow association to an external form
We will register a new mfa-button
(mfa – material form associated) and replace mwc-button
with mfa-button
in the template file.
You can see it working in Example 3:
Example 3: Same simple form shown in Example 2, this time with the
mfa-button
. Note that validation works again as well as submission and reset.
Click here for the full commit diff
Here’s the extended button’s code:
In the button’s constructor, we add a listener that handles a click and fires _handleClick
.
The magic happen inside _handleClick
: we get the form either by id or the closest form. If the form exists, we either reset it or submit it.
Note we use requestSubmit
and not simple submit
. This is in order to emulate a submit via a button and enact all the form’s goodies like validation.
Summary
In this article we saw that web components might not always play “out of the box” with the bigger apps.
In this case, we saw that a simple button stopped interacting with the hosting form. We solved it by implementing the form API and “manually” associating the button with the form.
Worth to note that’s a spec is on its way (for quite a while) to solve this. Since it isn’t here now and it does not even appear in caniuse.com, we had to find another solution for our custom form elements to be associated with a form.
In the next article I’ll explain how we can associate input elements with a form (hint: it could have been similar if not for Safari…).
In the meantime I recommend cloning the repository and checking out the form-association-demo
branch. You could try to add a reset button or one of the mwc
input elements like @material/text-field
and see if you can make it work the same way.
Hope you learned something new 🙂
As usual, your comments are more than welcome!
Thanks a lot to Yonatan Doron from Hodash.dev for a thorough review!
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK