From c18ef3c959b6cf6a275870a503383097e3930add Mon Sep 17 00:00:00 2001 From: Domenic Denicola Date: Thu, 23 May 2019 14:19:52 -0400 Subject: [PATCH] Allow setting default accessibility semantics for custom elements --- source | 164 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 158 insertions(+), 6 deletions(-) diff --git a/source b/source index 23deae16cf8..c03282c7af9 100644 --- a/source +++ b/source @@ -4015,6 +4015,9 @@ a.setAttribute('href', 'https://example.com/'); // change the content attribute @@ -12833,8 +12836,38 @@ interface DOMStringMap {

Requirements related to ARIA and to platform accessibility APIs

User agent requirements for implementing Accessibility API semantics on HTML - elements are defined in HTML Accessibility API Mappings.

+ elements are defined in HTML Accessibility API Mappings. In addition to the + rules there, for a custom element element, the default WAI-ARIA role + semantics are determined as follows:

+ +
    +
  1. Let map be element's native accessibility semantics + map.

  2. + +
  3. If map["role"] exists, + then return it.

  4. + +
  5. Otherwise, return no role.

  6. +
+ +

Similarly, for a custom element element, the default WAI-ARIA state and + property semantics, for a state or property named stateOrProperty, are determined as + follows:

+ +
    +
  1. Let map be element's native accessibility semantics + map.

  2. + +
  3. If map[stateOrProperty] exists, + then return it.

  4. + +
  5. Otherwise, return the default value for stateOrProperty.

  6. +
+ +

For an example of this in action, see the + custom elements section.

+ +

Conformance checker requirements for checking use of ARIA role and aria-* attributes on @@ -66449,6 +66482,61 @@ customElements.define('my-checkbox', MyCheckbox); </form> +

Creating a custom element with default accessible roles, states, and properties
+ + + +

By using the appropriate properties of ElementInternals, your custom element can + have default accessibility semantics. The following code expands our form-associated checkbox from + the previous section to properly set its default role and checkedness, as viewed by accessibility + technology:

+ +
class MyCheckbox extends HTMLElement {
+  static get formAssociated() { return true; }
+
+  constructor() {
+    super();
+    this._internals = this.attachInternals();
+    this._checked = false;
+    this.addEventListener('click', this._onClick.bind(this));
+
+    this._internals.role = "checkbox";
+    this._internals.ariaChecked = false;
+  }
+
+  get form() { return this._internals.form; }
+  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;
+  }
+
+  _onClick(event) {
+    this.checked = !this._checked;
+  }
+}
+customElements.define('my-checkbox', MyCheckbox);
+ +

Note that, like for built-in elements, these are only defaults, and can be overridden by the + page author using the role and aria-* attributes:

+ +
<!-- This markup is non-conforming -->
+<input type="checkbox" checked role="button" aria-checked="false">
+
+<my-checkbox role="button" aria-checked="false">
+<script>
+  document.querySelector('my-checkbox').checked = true;
+</script>
+ +

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 + example, the author of the my-checkbox element would state that its role + and aria-checked values are strong native semantics, thus discouraging code such as the above.

Creating a customized built-in element
@@ -67995,6 +68083,8 @@ interface ElementInternals { readonly attribute NodeList labels; }; +ElementInternals includes AccessibilityMixin; + dictionary ValidityStateFlags { boolean valueMissing = false; boolean typeMismatch = false; @@ -68066,8 +68156,8 @@ dictionary ValidityStateFlags { checkValidity()

Returns true if internals's target element has no validity problems; false otherwise. - Fires an invalid event at the element in the latter case. -

+ Fires an invalid event at the element in the latter + case.

valid = internals . reportValidity()
@@ -68078,8 +68168,19 @@ dictionary ValidityStateFlags {
internals . labels

Returns a NodeList of all the label elements that - internals's target element is associated with. -

+ internals's target element is associated + with.

+ +
internals . role [ = value ]
+

Sets or retrieves the default ARIA role for internals's target element, which will be used unless the page author + overrides it using the role attribute.

+ +
internals . aria* [ = value ]
+

Sets or retrieves various default ARIA states or property values for + internals's target element, which will be used + unless the page author overrides them using the aria-* + attributes.

@@ -68290,6 +68391,57 @@ dictionary ValidityStateFlags { +
+ +

By using the role and aria* properties + of ElementInternals, custom element can set default accessibile roles, states, and + property values for their custom element, similar to how native elements behave. See the example above for more details.

+ +
+ +

Each custom element has a native accessibility semantics map, which is + a map. See the Requirements related to ARIA and to platform + accessibility APIs section for information on how this impacts platform accessibility + APIs.

+ +

ElementInternals includes the AccessibilityMixin mixin. The IDL + attributes provided by this mixin are used to manipulate the target element's native accessibility semantics + map, as follows:

+ +

To get the accessibility IDL attribute + for ElementInternals, given internals, idlAttribute, and + contentAttribute:

+ +
    +
  1. Let map be this ElementInternals's target element's native accessibility semantics + map.

  2. + +
  3. If map[contentAttribute] exists, + then return it.

  4. + +
  5. Return null.

  6. +
+ +

To set the accessibility IDL attribute for ElementInternals, given + internals, idlAttribute, contentAttribute, and + value:

+ +
    +
  1. Let map be this ElementInternals's target element's native accessibility semantics + map.

  2. + +
  3. If value is null, then remove + map[contentAttribute].

  4. + +
  5. Otherwise, set map[contentAttribute] to value.

  6. +
+ +
+

Common idioms without dedicated elements

Bread crumb navigation