Form-Associated Elements
What are form-associated custom elements
Section titled “What are form-associated custom elements”The Form-Associated Custom Elements API lets a custom element participate in a <form> exactly like a native input. The element reports its value, validity, and can be included in FormData and form.submit().
Without this API, a custom element placed inside a <form> is invisible to the browser’s form submission machinery. Values it holds are not serialised, and built-in validation does not apply to it. With the API, your element becomes a first-class form participant indistinguishable from a native <input>.
Enabling the API
Section titled “Enabling the API”Two things are required: a static formAssociated = true property on the class, and a call to this.attachInternals() in the constructor.
class MyInput extends HTMLElement { static formAssociated = true; constructor() { super(); this.internals = this.attachInternals(); }}The static property must be declared before attachInternals() is called — the browser reads it at construction time to decide whether to grant form-participation abilities.
ElementInternals methods
Section titled “ElementInternals methods”Once you have the internals object, these are the key form-related methods:
internals.setFormValue(value)— sets the value included inFormDatawhen the form is submitted.internals.setValidity(flags, message, anchor)— controls the element’s validation state. Pass an empty object and an empty string to clear all errors.internals.reportValidity()— triggers the browser’s built-in validation UI (the tooltip bubble), the same way a native input would.internals.checkValidity()— returns a boolean indicating whether the element currently passes validation.
The internals.role and ARIA reflection properties are covered in the Accessibility lesson.
Full API reference
Section titled “Full API reference”// Form-Associated Custom Elements API (Chrome 77+, Firefox 98+, Safari 16.4+)// static formAssociated = true — must be on the class before attachInternals()// this.internals = this.attachInternals()//// internals.setFormValue(value) — submittable value// internals.setFormValue(value, state) — value + restore-state hint// internals.setValidity({}, '') — clear validity errors// internals.setValidity({ valueMissing: true }, 'Required', anchorEl)// internals.reportValidity() — show browser validation UI// internals.checkValidity() — boolean// internals.form — the associated <form> element// internals.labels — NodeList of associated <label>s// internals.willValidate — booleanRunnable demo — feature-detected
Section titled “Runnable demo — feature-detected”The demo below feature-detects support for attachInternals and formAssociated. If the browser does not support them, a fallback message is shown instead.
Type into the custom input and watch the paragraph below the form reflect the value that would be submitted with the form.