-
Notifications
You must be signed in to change notification settings - Fork 3k
Description
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-inbutton
- for button like behaviorsubmit
- for submit button like behaviorreset
- for reset button like behaviorlabel
- 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