search
HomeWeb Front-endCSS TutorialCreating Custom Form Controls with ElementInternals

Creating Custom Form Controls with ElementInternals

Developers have long been eager to have more control over form elements. While this is a bit exaggerated, creating or customizing form components has been the holy grail of front-end web development for years.

Custom elements (e.g.<my-custom-element></my-custom-element> ) One of the most powerful features, has been quietly released since the Google Chrome 77 version and has been gradually applied to other browsers. The ElementInternals standard is a powerful set of features with a very low-key name. Its features include participating forms and APIs surrounding accessibility controls.

This article will explore how to create custom form controls, integrate constraint verification, introduce the basics of internal accessibility, and show how to combine these features to create highly portable macro form controls.

Let's start by creating a simple custom element that matches our design system. Our elements will save all styles in shadow DOM and ensure some basic accessibility. We will use the excellent LitElement library from the Google Polymer team as our code example, and while you absolutely don't need it, it does provide a good abstraction for writing custom elements.

In this example, we create a<rad-input></rad-input> , it has some basic designs. We also added a second input to the form, which is a normal HTML input, and added the default value (so you can just press submit and see how it works).

When we click the Submit button, several things happen. First, the preventDefault method of the commit event is called, in this case, to ensure that our page does not reload. After that, we create a FormData object that allows us to access information about the form, which we use to construct a JSON string and append it to<output></output> element. However, note that the unique value added to our output comes from an element named "basic".

This is because our elements don't know how to interact with the form yet, so let's set up ours using the ElementInternals instance<rad-input></rad-input> , to help it deserve its name. First, we need to call the attachInternals method of our method in the element's constructor, and we will also import the ElementInternals polyfill into our page for use with browsers that do not yet support the specification.

The attachInternals method returns a new element internal instance containing some new APIs that we can use in our methods. In order for our elements to take advantage of these APIs, we need to add a static formAssociated getter that returns true .

 class RadInput extends LitElement {
  static get formAssociated() {
    return true;
  }

  constructor() {
    super();
    this.internals = this.attachInternals();
  }
}

Let's take a look at some APIs in internals attribute of an element:

  • setFormValue(value: string|FormData|File, state?: any): void — This method sets the value of an element on its parent form if the parent form exists. If the value is null, the element will not participate in the form submission process.
  • form — If present, it is a reference to the parent form of the element.
  • setValidity(flags: Partial<validitystate> , message?: string, anchor?: HTMLElement): void</validitystate> — the setValidity method will help control the validity status of elements in the form. If the form is invalid, a verification message must exist.
  • willValidate — true if the element is evaluated when the form is submitted.
  • validity — A validity object that matches the API and semantics attached to HTMLInputElement.prototype.validity .
  • validationMessage — If you setValidity to invalidate the control, this is the message describing the error.
  • checkValidity — Returns true if the element is valid, otherwise returns false and triggers an invalid event on the element.
  • reportValidity — Same as checkValidity , if the event is not cancelled, a problem is reported to the user.
  • labels — Use label[for] attribute to mark the list of elements for this element.
  • Some other controls for setting aria information on elements.

Set the value of a custom element

Let's modify ours<rad-input></rad-input> To take advantage of some of these APIs:

Here we modify the element's _onInput method to contain a call to this.internals.setFormValue . This tells the form that our element wants to register a value in the form using its given name (set as a property in our HTML). We also added a firstUpdated method (similar to connectedCallback when not using LitElement) which sets the element's value to an empty string when the element is finished rendering. This is to ensure that our elements always have the value of the form (although not required, you can exclude the elements from the form by passing in a null value).

Now when we add value to the input and submit the form we will be in our<output></output> A radInput value is seen in the element. We can also see that our element has been added to the radInput property of HTMLFormElement . However, one thing you may have noticed is that it still allows form submission despite our element having no value. Next, let's add some validation to our element.

Add constraint verification

To set the validation of the field, we need to modify the element a little to use the setValidity method on the object inside the element. This method will accept three parameters (if the element is invalid, only the second parameter is required, and the third parameter is always optional). The first parameter is part of ValidityState object. If any flag is set to true, the control will be marked as invalid. If one of the built-in validity keys does not meet your needs, you can use the common customError key. Finally, if the control is valid, we will pass in an object literal ({}) to reset the control's validity.

The second parameter is the validity message of the control. This parameter is required if the control is invalid, and this parameter is not allowed if the control is valid. The third parameter is an optional verification target, which will control the user's focus if the form submission is invalid or if reportValidity is called.

We will give our<rad-input></rad-input> Introduce a new method to handle this logic:

 _manageRequired() {
  const { value } = this;
  const input = this.shadowRoot.querySelector('input');
  if (value === '' && this.required) {
    this.internals.setValidity({
      valueMissing: true
    }, 'This field is required', input);
  } else {
    this.internals.setValidity({});
  }
}

This function gets the value and input of the control. If the value is equal to an empty string and the element is marked as required, we will call internals.setValidity and toggle the validity of the control. Now all we need to do is call this method in our firstUpdated and _onInput methods, and we can add some basic validation to our elements.

In the absence of our<rad-input></rad-input> Before entering the value, click the Submit button and the error message will now be displayed in browsers that support the ElementInternals specification. Unfortunately, polyfill still does not support displaying verification errors , as there is no reliable way to trigger the built-in verification popup in unsupported browsers.

We also added some basic accessibility information to our example by using our internals object. We add an additional property _required to the element, which will act as a proxy for this.required and a getter/setter for required .

 get required() {
  return this._required;
}

set required(isRequired) {
  this._required = isRequired;
  this.internals.ariaRequired = isRequired;
}

By passing the required property to internals.ariaRequired , we are reminding the screen reader that our element currently needs a value. In polyfill, this is done by adding the aria-required attribute; however, in supported browsers, the attribute is not added to the element because the attribute is inherent to the element.

Create a micro form

Now that we have a valid input that fits our design system, we may want to start combining our elements into patterns that can be reused across multiple applications. One of the most eye-catching features of ElementInternals is that the setFormValue method can take not only string and file data, but also FormData objects. So, suppose we want to create a common address form that might be used in multiple organizations, we can do this easily with our newly created elements.

In this example, we create a form within the shadow root of the element, in which we combine four<rad-input></rad-input> Element to create an address form. Instead of calling setFormValue with a string this time, we choose to pass the entire value of the form. As a result, our element passes the value of each individual element within its child form to the external form.

Adding constraint validation to this form would be a fairly simple process, as would providing additional styling, behavior, and content slots. Using these newer APIs ultimately allows developers to unlock a lot of potential in custom elements and ultimately gives us the freedom to control the user experience.

The above is the detailed content of Creating Custom Form Controls with ElementInternals. For more information, please follow other related articles on the PHP Chinese website!

Statement
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Demystifying Screen Readers: Accessible Forms & Best PracticesDemystifying Screen Readers: Accessible Forms & Best PracticesMar 08, 2025 am 09:45 AM

This is the 3rd post in a small series we did on form accessibility. If you missed the second post, check out "Managing User Focus with :focus-visible". In

Create a JavaScript Contact Form With the Smart Forms FrameworkCreate a JavaScript Contact Form With the Smart Forms FrameworkMar 07, 2025 am 11:33 AM

This tutorial demonstrates creating professional-looking JavaScript forms using the Smart Forms framework (note: no longer available). While the framework itself is unavailable, the principles and techniques remain relevant for other form builders.

Adding Box Shadows to WordPress Blocks and ElementsAdding Box Shadows to WordPress Blocks and ElementsMar 09, 2025 pm 12:53 PM

The CSS box-shadow and outline properties gained theme.json support in WordPress 6.1. Let's look at a few examples of how it works in real themes, and what options we have to apply these styles to WordPress blocks and elements.

Working With GraphQL CachingWorking With GraphQL CachingMar 19, 2025 am 09:36 AM

If you’ve recently started working with GraphQL, or reviewed its pros and cons, you’ve no doubt heard things like “GraphQL doesn’t support caching” or

Making Your First Custom Svelte TransitionMaking Your First Custom Svelte TransitionMar 15, 2025 am 11:08 AM

The Svelte transition API provides a way to animate components when they enter or leave the document, including custom Svelte transitions.

Comparing the 5 Best PHP Form Builders (And 3 Free Scripts)Comparing the 5 Best PHP Form Builders (And 3 Free Scripts)Mar 04, 2025 am 10:22 AM

This article explores the top PHP form builder scripts available on Envato Market, comparing their features, flexibility, and design. Before diving into specific options, let's understand what a PHP form builder is and why you'd use one. A PHP form

Show, Don't TellShow, Don't TellMar 16, 2025 am 11:49 AM

How much time do you spend designing the content presentation for your websites? When you write a new blog post or create a new page, are you thinking about

What the Heck Are npm Commands?What the Heck Are npm Commands?Mar 15, 2025 am 11:36 AM

npm commands run various tasks for you, either as a one-off or a continuously running process for things like starting a server or compiling code.

See all articles

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

AI Hentai Generator

AI Hentai Generator

Generate AI Hentai for free.

Hot Article

R.E.P.O. Energy Crystals Explained and What They Do (Yellow Crystal)
2 weeks agoBy尊渡假赌尊渡假赌尊渡假赌
Repo: How To Revive Teammates
4 weeks agoBy尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island Adventure: How To Get Giant Seeds
4 weeks agoBy尊渡假赌尊渡假赌尊渡假赌

Hot Tools

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

This project is in the process of being migrated to osdn.net/projects/mingw, you can continue to follow us there. MinGW: A native Windows port of the GNU Compiler Collection (GCC), freely distributable import libraries and header files for building native Windows applications; includes extensions to the MSVC runtime to support C99 functionality. All MinGW software can run on 64-bit Windows platforms.

SAP NetWeaver Server Adapter for Eclipse

SAP NetWeaver Server Adapter for Eclipse

Integrate Eclipse with SAP NetWeaver application server.

MantisBT

MantisBT

Mantis is an easy-to-deploy web-based defect tracking tool designed to aid in product defect tracking. It requires PHP, MySQL and a web server. Check out our demo and hosting services.

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)