From e32a070cbd6c04fe8a82090abeb4d022ecc8a557 Mon Sep 17 00:00:00 2001
From: Domenic Denicola Finally, the following terms are defined ARIA:
+
ARIAMixin
interface, with its associated
get the accessibility IDL attribute and
@@ -66449,11 +66450,11 @@ document.body.appendChild(flagIcon)
get name() { return this.getAttribute('name'); }
get type() { return this.localName; }
- get checked() { return this._checked; }
- set checked(flag) {
- this._checked = !!flag;
- this._internals.setFormValue(this._checked ? 'on' : null);
+ get checked() { return this.getAttribute('checked'); }
+ set checked(flag) { this.toggleAttribute('checked', Boolean(flag)); }
+
+ attributeChangedCallback(name, oldValue, newValue) {
+ // name will always be "checked" due to observedAttributes
+ this._internals.setFormValue(this.checked ? 'on' : null);
}
_onClick(event) {
- this.checked = !this._checked;
+ this.checked = !this.checked;
}
}
customElements.define('my-checkbox', MyCheckbox);
@@ -66496,11 +66499,11 @@ customElements.define('my-checkbox', MyCheckbox);
class MyCheckbox extends HTMLElement {
static get formAssociated() { return true; }
+ static get observedAttributes() { return ['checked']; }
constructor() {
super();
this._internals = this.attachInternals();
- this._checked = false;
this.addEventListener('click', this._onClick.bind(this));
}
@@ -66461,14 +66462,16 @@ document.body.appendChild(flagIcon)
get name() { return this.getAttribute('name'); }
get type() { return this.localName; }
- get checked() { return this._checked; }
- set checked(flag) {
- this._checked = !!flag;
- this._internals.setFormValue(this._checked ? 'on' : null);
- this._internals.ariaChecked = this._checked;
+ get checked() { return this.getAttribute('checked'); }
+ set checked(flag) { this.toggleAttribute('checked', Boolean(flag)); }
+
+ attributeChangedCallback(name, oldValue, newValue) {
+ // name will always be "checked" due to observedAttributes
+ this._internals.setFormValue(this.checked ? 'on' : null);
+ this._internals.ariaChecked = this.checked;
}
_onClick(event) {
- this.checked = !this._checked;
+ this.checked = !this.checked;
}
}
customElements.define('my-checkbox', MyCheckbox);
@@ -66529,12 +66534,10 @@ customElements.define('my-checkbox', MyCheckbox);
data-x="attr-aria-*">aria-* attributes:class MyCheckbox extends HTMLElement {
static get formAssociated() { return true; }
+ static get observedAttributes() { return ['checked']; }
constructor() {
super();
this._internals = this.attachInternals();
- this._checked = false;
this.addEventListener('click', this._onClick.bind(this));
this._internals.role = 'checkbox';
@@ -66511,15 +66514,17 @@ customElements.define('my-checkbox', MyCheckbox);
<!-- This markup is non-conforming -->
-<input type="checkbox" checked role="button" aria-checked="false">
+<input type="checkbox" checked role="button" aria-checked="false">
-<my-checkbox role="button" aria-checked="false">
-<script>
- document.querySelector('my-checkbox').checked = true;
-</script>
+<!-- This markup is probably not what the custom element author intended -->
+<my-checkbox role="button" checked aria-checked="false">
Custom element authors are encouraged to state what aspects of their accessibility semantics
are strong native semantics, i.e., should not be overriden by users of the custom element. In our
@@ -66658,16 +66661,16 @@ console.log(plasticButton.outerHTML); // will output '<button is="plastic-but
taco-button
were to become logically disabled, the tabindex
attribute would need to be removed.
The addition of various ARIA attributes helps convey semantics to accessibility
- technology. For example, setting the role
attribute to
- "button
" will convey the semantics that this is a
- button, enabling users to successfully interact with the control using usual button-like
- interactions in their accessibility technology. Setting the aria-label
attribute is necessary to give the button an
- accessible name, instead of having accessibility
- technology traverse its child text nodes and announce them. And setting aria-disabled
to "true
" when the button
- is logically disabled conveys to accessibility technology the button's disabled state.
The addition of an ARIA role and various ARIA states and properties helps convey semantics
+ to accessibility technology. For example, setting the role to "button
" will convey the semantics that this is a button,
+ enabling users to successfully interact with the control using usual button-like interactions in
+ their accessibility technology. Setting the aria-label
+ property is necessary to give the button an accessible
+ name, instead of having accessibility technology traverse its child text nodes and
+ announce them. And setting the aria-disabled
state to
+ "true
" when the button is logically disabled conveys to accessibility
+ technology the button's disabled state.
The addition of event handlers to handle commonly-expected button behaviors helps convey the semantics of the button to Web browser users. In this case, the most relevant event handler @@ -66691,9 +66694,11 @@ console.log(plasticButton.outerHTML); // will output '<button is="plastic-but constructor() { super(); + this._internals = this.attachInternals(); + this._internals.role = "button"; this.addEventListener("keydown", e => { - if (e.keyCode === 32 || e.keyCode === 13) { + if (e.code === "Enter" || e.code === "Space") { this.dispatchEvent(new MouseEvent("click", { bubbles: true, cancelable: true @@ -66704,17 +66709,16 @@ console.log(plasticButton.outerHTML); // will output '<button is="plastic-but this.addEventListener("click", e => { if (this.disabled) { e.preventDefault(); - e.stopPropagation(); + e.stopImmediatePropagation(); } }); this._observer = new MutationObserver(() => { - this.setAttribute("aria-label", this.textContent); + this._internals.ariaLabel = this.textContent; }); } connectedCallback() { - this.setAttribute("role", "button"); this.setAttribute("tabindex", "0"); this._observer.observe(this, { @@ -66731,33 +66735,29 @@ console.log(plasticButton.outerHTML); // will output '<button is="plastic-but get disabled() { return this.hasAttribute("disabled"); } - - set disabled(v) { - if (v) { - this.setAttribute("disabled", ""); - } else { - this.removeAttribute("disabled"); - } + set disabled(flag) { + this.toggleAttribute("disabled", Boolean(flag)); } - attributeChangedCallback() { - // only is called for the disabled attribute due to observedAttributes + attributeChangedCallback(name, oldValue, newValue) { + // name will always be "disabled" due to observedAttributes if (this.disabled) { this.removeAttribute("tabindex"); - this.setAttribute("aria-disabled", "true"); + this._internals.ariaDisabled = "true"; } else { this.setAttribute("tabindex", "0"); - this.setAttribute("aria-disabled", "false"); + this._internals.ariaDisabled = "false"; } } }
Even with this rather-complicated element definition, the element is not a pleasure to use for
- consumers: it will be continually "sprouting" tabindex
and
- aria-*
attributes of its own volition. This is because as of now
- there is no way to specify default accessibility semantics or focus behavior for custom elements,
- forcing the use of these attributes to do so (even though they are usually reserved for allowing
- the consumer to override default behavior).
tabindex
+ attributes of its own volition, and its choice of tabindex="0"
focusability
+ behavior may not match the button
behavior on the current platform. This is because
+ as of now there is no way to specify default focus behavior for custom elements, forcing the use
+ of the tabindex
attribute to do so (even though it is usually
+ reserved for allowing the consumer to override default behavior).
In contrast, a simple customized built-in element, as shown in the previous
section, would automatically inherit the semantics and behavior of the button