Skip to content

Proposal: Customized built-in elements via elementInternals.type #11061

@sanketj

Description

@sanketj

What problem are you trying to solve?

Web component authors often want to create custom elements that inherit the behaviors and properties of native HTML elements. These types of custom elements are referred to as "customized built-in elements" or just "customized built-ins". By customizing built-in elements, custom elements can leverage the built-in functionality of standard elements while extending their capabilities to meet specific needs. Some of the use cases enabled by customized built-ins are listed below.

  • Custom buttons can provide unique styles and additional functionality, such as split or toggle button semantics, while still maintaining native button behavior such as being a popover invoker.
  • Custom buttons can extend native submit button behavior so that the custom button can implicitly submit forms. Similarly, custom buttons that extend native reset button behavior can implicitly reset forms.
  • Custom labels can provide additional functionality, such as tooltips and icons, while still supporting associations with labelable elements via the for attribute or nesting a labelable element inside the custom label.

What solutions exist today?

A partial solution for this problem already exists today. Authors can specify the extends option when defining a custom element. Authors can then use the is attribute to give a built-in element a custom name, thereby turning it into a customized built-in element.

Both extends and is are supported in Firefox and Chromium-based browsers . However, this solution has limitations, such as not being able to attach shadow trees to (most) customized built-in elements. Citing these limitations, Safari doesn't plan to support customized built-ins in this way and have shared their objections here: WebKit/standards-positions#97 (comment). As such, extends and is are not on a path to full interoperability today.

How would you solve it?

The ElementInternals interface gives web developers a way to participate in HTML forms and integrate with the accessibility OM. This will be extended to support the creation of customized built-ins by adding a type property, which can be set to string values that represent native element types. The initial set of type values being proposed are listed below. Support for additional values may be added in the future.

  • '' (empty string) - this is the default value, indicating the custom element is not a customized built-in
  • button - for button like behavior
  • submit - for submit button like behavior
  • reset - for reset button like behavior
  • label - for label like behavior

This proposal was presented and discussed at TPAC, where it was resolved by the WHATWG to add elementInternals.type = 'button' to the HTML spec.
Initial proposal discussed at TPAC: openui/open-ui#1088 (comment)
WHATWG resolution for elementInternals.type = 'button': openui/open-ui#1088 (comment)

This issue formally tracks the proposal against the @whatwg/html repo and also includes a few additional types beyond button that had support at TPAC.

Full explainer here: https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/ElementInternalsType/explainer.md

Examples

Below is an example showcasing a custom button being used as a popup invoker. When the custom button is activated, ex. via a click, div id="my-popover will be shown as a popover.

    class CustomButton extends HTMLElement {
        static formAssociated = true;

        constructor() {
            super();
            this.internals_ = this.attachInternals();
            this.internals_.type = 'button';
        }
    }
    customElements.define('custom-button', CustomButton);
    <custom-button popovertarget="my-popover">Open popover</custom-button>
    <div id="my-popover" popover>This is popover content.</div>

Like with native buttons, if the disabled attribute is set, a custom button cannot be activated and thus cannot invoke popovers.


Below is an example showcasing a custom submit button being used to submit a form. When the custom button is activated, ex. via a click, the form will be submitted and the page will navigate.

    class CustomSubmitButton extends HTMLElement {
        static formAssociated = true;

        constructor() {
            super();
            this.internals_ = this.attachInternals();
            this.internals_.type = 'submit';
        }
    }
    customElements.define('custom-submit-button', CustomSubmitButton);
    <form action="http://www.bing.com">
        <custom-submit-button>Submit</custom-submit-button>
    </form>

If the disabled attribute is set on a custom submit button, it cannot be activated and thus cannot submit forms.


Below is an example showcasing a custom label being used to label a checkbox. When the custom label is activated, ex. via a click, the checkbox is also activated, resulting in its state changing to checked.

    class CustomLabel extends HTMLElement {
        static formAssociated = true;

        constructor() {
            super();
            this.internals_ = this.attachInternals();
            this.internals_.type = 'label';
        }
    }
    customElements.define('custom-label', CustomLabel);
   <custom-label for='my-checkbox'>Toggle checkbox</custom-label>
   <input type='checkbox' id='my-checkbox' />

cc: @alexkeng

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions