We’re happy to announce that as of version 4.5.0, Stencil now
has support for building form-associated custom elements! This new feature allows you to build rich, new
user experiences leveraging form-related functionality that’s
already built-in to the browser, like validation, accessibility,
and more.
What are form-associated custom elements?
The browser comes out-of-the-box with several form controls that
you can use to declaratively build out a form without having to
manually wire anything up. You just nest your
<input>
, <select>
, and
<textarea>
elements inside a
<form>
element and the values from those inputs
will be automatically bundled up together. These inputs can also
report whether they are in a valid or invalid state, they can be
labeled for accessibility, and more.
With form-associated custom elements and the
ElementInternals
interface, these built-in browser
features are opened up to web component developers, who can use
them to build custom elements which participate in form elements in
a rich way, just like the inputs already shipped by the
browser.
If you want to learn more about form-associated custom elements, check out this blog post from the WebKit team, this article from web.dev, or read through the WHATWG specification.
Show me an example!
To bring support for form-associated custom elements to Stencil
we’re adding two things: a new option, formAssociated
,
for the @Component
decorator, and a new decorator,
@AttachInternals
, which will give you access to the
ElementInternals
for your component.
A Stencil component using this API to implement a custom text input could look
like this:
import { AttachInternals, Component, h, State } from '@stencil/core';
@Component({
tag: 'custom-text-input',
shadow: true,
formAssociated: true
})
export class CustomTextInput {
@State() value: string;
@AttachInternals() internals: ElementInternals;
handleChange(event) {
this.value = event.target.value;
this.internals.setFormValue(event.target.value);
}
componentWillLoad() {
this.internals.setFormValue("a default value");
}
render() {
return (
<input
type="text"
value={this.value}
onInput={(event) => this.handleChange(event)}
/>
)
}
}
If this component is rendered within a <form>
element like so:
<form>
<custom-text-input name="my-custom-input"></custom-text-input>
</form>
Then it will automatically be linked up to the surrounding form,
and the ElementInternals
object found at
this.internals
will have methods on it for interacting
with that form and accessing key information.
In our <custom-text-input>
example above, we
use the setFormValue
method to set a value
in the surrounding form. This will read the name
attribute on the element and use it when setting the value, so the
value typed by a user into the input
will be added to
the form under the "my-custom-input"
name.
With the above example, you could demonstrate this by printing the form data like so:
const form = document.querySelector("form");
const formData = new FormData(form);
console.log("~~ current form state ~~")
for (let entry of formData.entries()) {
console.log(`${entry[0]}: ${entry[1]}`);
}
This example just scratches the surface, and a great deal more
is possible with the ElementInternals
API, including
setting the element’s validity, reading the
validity state of the form, reading other form values, and
more.
This feature brings a lot of functionality to Stencil components that interact with forms and we can’t wait to see what you build with it!
The post Announcing Support for Form-Associated Custom Elements in Stencil v4.5.0 appeared first on Ionic Blog.
Read more https://ionic.io/blog/announcing-support-for-form-associated-custom-elements-in-stencil-v4-5-0