Technical Notes

Technical Challenges

A form input element rendered inside the code component’s Shadow DOM will not be serialized by the outer HTML <form> on submit. Forms only submit light-DOM controls or form-associated custom elements (FACE).

Ways to make it work:

Slot the real input (best, native submit)

<!-- In the component's shadow: -->
<slot name="ctrl"></slot>

<!-- In your form (light DOM): -->
<form>
  <code-island> <!-- your component host -->
    <input type="checkbox" slot="ctrl" name="agree" value="1">
  </code-island>
  <button type="submit">Send</button>
</form>

The checkbox stays in light DOM β†’ included in submission.

Mirror to a hidden input (when the component must render its own UI)

Inside the React component (run in the shadow root), dispatch a composed event on change:

Intercept submit and append programmatically (no hidden input)

Pick 1 if you can control markup; 2 if you want native posts with minimal JS; 3 if you already handle submissions via JS.

Form-Associated Custom Elements (FACE)

Form-associated custom elements (FACE) are custom elements that participate in HTML forms like native inputs.

Key points

  • Opt-in: static formAssociated = true; then this.internals = this.attachInternals().

  • Association: the element is owned by the nearest <form> or by form="<form id>" even if placed outside. Access via this.internals.form.

  • Submission: give the element a name attribute and call this.internals.setFormValue(value) whenever its value changes; the value is included in form FormData.

  • Labels: this.internals.labels returns associated <label>s.

  • Validation: use this.internals.setValidity(...), checkValidity(), reportValidity(), willValidate, validationMessage.

  • Lifecycle hooks: formAssociated(form), formDisabledCallback(disabled), formResetCallback(), formStateRestoreCallback(state,mode).

Minimal example (TypeScript)

Usage (native submit)

Notes

  • Must have a name to be serialized.

  • Works with the formdata and normal form submission flows.

  • Broad support in Chromium-based browsers and Safari; Firefox does not support FACE as of now.

Last updated