Skip to content

Commit

Permalink
Generalize AccessibilityRole/AriaAttributes IDL (#984)
Browse files Browse the repository at this point in the history
* Generalize AccessibilityRole/AriaAttributes IDL

This generalizes the AccessibilityRole/AriaAttributes IDL mixins to allow them to have different behaviors per host interface. For Element, they have the reflection behavior specified, but e.g. for ElementInternals, HTML can use this framework to define different behavior.

In the process, this consolidates the two mixins into one ("ARIAMixin"), since this makes it easier to define their behavior uniformly, and consumers should generally not mix in one without the other.
  • Loading branch information
jnurthen committed Aug 31, 2022
1 parent f6290fe commit c171297
Showing 1 changed file with 113 additions and 74 deletions.
187 changes: 113 additions & 74 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2118,7 +2118,7 @@ <h2>Definition of Roles</h2>
</tr>
<tr>
<th class="role-properties-head" scope="row">Supported States and Properties:</th>
<td class="role-properties">
<td class="role-properties">
<ul>
<li><pref>aria-activedescendant</pref></li>
<li><pref>aria-autocomplete</pref></li>
Expand Down Expand Up @@ -10678,7 +10678,7 @@ <h2>Definitions of States and Properties (all aria-* attributes)</h2>
<tr>
<th class="property-descendants-head" scope="row">Inherits into Roles:</th>
<td class="property-descendants">Placeholder</td>
</tr>
</tr>
<tr>
<th class="property-value-head" scope="row">Value:</th>
<td class="property-value"><a href="#valuetype_idref">ID reference</a></td>
Expand Down Expand Up @@ -10849,8 +10849,8 @@ <h2>Definitions of States and Properties (all aria-* attributes)</h2>
<p>The <code>aria-haspopup</code> property is a token type. [=User agents=] MUST treat any value of <code>aria-haspopup</code> that is not included in the list of allowed values, including an empty string, as if the value <code>false</code> had been provided. To provide backward compatibility with ARIA 1.0 content, user agents MUST treat an <code>aria-haspopup</code> value of <code>true</code> as equivalent to a value of <code>menu</code>.</p>
<p><a>Assistive technologies</a> SHOULD NOT expose the <code>aria-haspopup</code> property if it has a value of <code>false</code>.</p>
<p class="note">A <rref>tooltip</rref> is not considered to be a popup in this context.</p>
<p class="note"><code>aria-haspopup</code> is most relevant to use when there is a visual indicator in the element that triggers the popup.
For example, many controls styled with a downward pointing triangle, chevron, or ellipsis (three consecutive dots) have become standard visual indicators that a popup will display when the control is activated.
<p class="note"><code>aria-haspopup</code> is most relevant to use when there is a visual indicator in the element that triggers the popup.
For example, many controls styled with a downward pointing triangle, chevron, or ellipsis (three consecutive dots) have become standard visual indicators that a popup will display when the control is activated.
If some functional difference is relevant to display to a sighted user by means of a different visual style, that functional difference is usually relevant to convey to users of assistive technology.
If there is no visual indication that an element will trigger a popup, authors are advised to consider whether use of <code>aria-haspopup</code> is necessary, and avoid using it when it's not.
</p>
Expand Down Expand Up @@ -12750,22 +12750,13 @@ <h3>Presentational Roles Conflict Resolution</h3>
</section>
<section id="idl-interface" class="normative">
<h2>IDL Interface</h2>
<p>Conforming user agents MUST implement the following IDL interfaces.</p>
<section id="AccessibilityRole" class="normative" data-dfn-for="AccessibilityRole" data-link-for="AccessibilityRole">
<h2>Interface Mixin <dfn>AccessibilityRole</dfn></h2>
<p>Conforming user agents MUST implement the following IDL interface.</p>
<section id="ARIAMixin" class="normative" data-dfn-for="ARIAMixin" data-link-for="ARIAMixin">
<h2>Interface Mixin <dfn>ARIAMixin</dfn></h2>
<pre class="idl">
interface mixin AccessibilityRole {
attribute DOMString role;
};
Element includes AccessibilityRole;
</pre>
<p>User agents MUST <a href="https://html.spec.whatwg.org/multipage/common-dom-interfaces.html#reflecting-content-attributes-in-idl-attributes">reflect</a> the <code><dfn>role</dfn></code> content attribute as the <code>role</code> IDL attribute.</p>
</section>
interface mixin ARIAMixin {
attribute DOMString? role;

<section id="AriaAttributes" class="normative" data-dfn-for="AriaAttributes" data-link-for="AriaAttributes">
<h2>Interface Mixin <dfn>AriaAttributes</dfn></h2>
<pre class="idl">
interface mixin AriaAttributes {
<!-- attribute Element ariaActiveDescendantElement; -->
attribute DOMString ariaAtomic;
attribute DOMString ariaAutoComplete;
Expand Down Expand Up @@ -12816,63 +12807,93 @@ <h2>Interface Mixin <dfn>AriaAttributes</dfn></h2>
attribute DOMString ariaValueNow;
attribute DOMString ariaValueText;
};
Element includes AriaAttributes;
</pre>
<section id="reflection" class="normative">
<h2>ARIA Attribute Reflection</h2>
<p>User agents MUST <a href="https://html.spec.whatwg.org/multipage/common-dom-interfaces.html#reflecting-content-attributes-in-idl-attributes">reflect</a> the following content attributes to each of the corresponding IDL attributes.</p>
<table>
<tr><th>IDL Attribute</th><th>Reflected ARIA Content Attribute</th></tr>
<!-- <tr><td><dfn>ariaActiveDescendantElement</dfn></td><td><pref>aria-activedescendant</pref></td></tr> -->
<tr><td><dfn>ariaAtomic</dfn></td><td><pref>aria-atomic</pref></td></tr>
<tr><td><dfn>ariaAutoComplete</dfn></td><td><pref>aria-autocomplete</pref></td></tr>
<tr><td><dfn>ariaBusy</dfn></td><td><sref>aria-busy</sref></td></tr>
<tr><td><dfn>ariaChecked</dfn></td><td><sref>aria-checked</sref></td></tr>
<tr><td><dfn>ariaColCount</dfn></td><td><pref>aria-colcount</pref></td></tr>
<tr><td><dfn>ariaColIndex</dfn></td><td><pref>aria-colindex</pref></td></tr>
<tr><td><dfn>ariaColSpan</dfn></td><td><pref>aria-colspan</pref></td></tr>
<!-- <tr><td><dfn>ariaControlsElements</dfn></td><td><pref>aria-controls</pref></td></tr> -->
<tr><td><dfn>ariaCurrent</dfn></td><td><sref>aria-current</sref></td></tr>
<!-- <tr><td><dfn>ariaDescribedByElements</dfn></td><td><pref>aria-describedby</pref></td></tr> -->
<tr><td><dfn>ariaDescription</dfn></td><td><pref>aria-description</pref></td></tr>
<!-- <tr><td><dfn>ariaDetailsElements</dfn></td><td><pref>aria-details</pref></td></tr> -->
<tr><td><dfn>ariaDisabled</dfn></td><td><sref>aria-disabled</sref></td></tr>
<!-- <tr><td><dfn>ariaErrorMessageElement</dfn></td><td><pref>aria-errormessage</pref></td></tr> -->
<tr><td><dfn>ariaExpanded</dfn></td><td><sref>aria-expanded</sref></td></tr>
<!-- <tr><td><dfn>ariaFlowToElements</dfn></td><td><pref>aria-flowto</pref></td></tr> -->
<tr><td><dfn>ariaHasPopup</dfn></td><td><pref>aria-haspopup</pref></td></tr>
<tr><td><dfn>ariaHidden</dfn></td><td><sref>aria-hidden</sref></td></tr>
<tr><td><dfn>ariaInvalid</dfn></td><td><sref>aria-invalid</sref></td></tr>
<tr><td><dfn>ariaKeyShortcuts</dfn></td><td><pref>aria-keyshortcuts</pref></td></tr>
<tr><td><dfn>ariaLabel</dfn></td><td><pref>aria-label</pref></td></tr>
<!-- <tr><td><dfn>ariaLabelledByElements</dfn></td><td><pref>aria-labelledby</pref></td></tr> -->
<tr><td><dfn>ariaLevel</dfn></td><td><pref>aria-level</pref></td></tr>
<tr><td><dfn>ariaLive</dfn></td><td><pref>aria-live</pref></td></tr>
<tr><td><dfn>ariaModal</dfn></td><td><pref>aria-modal</pref></td></tr>
<tr><td><dfn>ariaMultiLine</dfn></td><td><pref>aria-multiline</pref></td></tr>
<tr><td><dfn>ariaMultiSelectable</dfn></td><td><pref>aria-multiselectable</pref></td></tr>
<tr><td><dfn>ariaOrientation</dfn></td><td><pref>aria-orientation</pref></td></tr>
<!-- <tr><td><dfn>ariaOwnsElements</dfn></td><td><pref>aria-owns</pref></td></tr> -->
<tr><td><dfn>ariaPlaceholder</dfn></td><td><pref>aria-placeholder</pref></td></tr>
<tr><td><dfn>ariaPosInSet</dfn></td><td><pref>aria-posinset</pref></td></tr>
<tr><td><dfn>ariaPressed</dfn></td><td><sref>aria-pressed</sref></td></tr>
<tr><td><dfn>ariaReadOnly</dfn></td><td><pref>aria-readonly</pref></td></tr>
<!-- <tr><td><dfn>ariaRelevant</dfn></td><td><pref>aria-relevant</pref></td></tr> -->
<tr><td><dfn>ariaRequired</dfn></td><td><pref>aria-required</pref></td></tr>
<tr><td><dfn>ariaRoleDescription</dfn></td><td><pref>aria-roledescription</pref></td></tr>
<tr><td><dfn>ariaRowCount</dfn></td><td><pref>aria-rowcount</pref></td></tr>
<tr><td><dfn>ariaRowIndex</dfn></td><td><pref>aria-rowindex</pref></td></tr>
<tr><td><dfn>ariaRowSpan</dfn></td><td><pref>aria-rowspan</pref></td></tr>
<tr><td><dfn>ariaSelected</dfn></td><td><sref>aria-selected</sref></td></tr>
<tr><td><dfn>ariaSetSize</dfn></td><td><pref>aria-setsize</pref></td></tr>
<tr><td><dfn>ariaSort</dfn></td><td><pref>aria-sort</pref></td></tr>
<tr><td><dfn>ariaValueMax</dfn></td><td><pref>aria-valuemax</pref></td></tr>
<tr><td><dfn>ariaValueMin</dfn></td><td><pref>aria-valuemin</pref></td></tr>
<tr><td><dfn>ariaValueNow</dfn></td><td><pref>aria-valuenow</pref></td></tr>
<tr><td><dfn>ariaValueText</dfn></td><td><pref>aria-valuetext</pref></td></tr>
</table>
<p class="note">Note: Attributes <pref>aria-dropeffect</pref> and <sref>aria-grabbed</sref> were deprecated in ARIA 1.1 and do not have corresponding IDL attributes.</p>
</section>

<p>Interfaces that include <code>ARIAMixin</code> must provide the following algorithms:</p>

<ul>
<li><dfn><code>ARIAMixin</code> getter steps</dfn>, which take the host interface instance, IDL attribute name, and content attribute name, and must return a string value; and
<li><dfn><code>ARIAMixin</code> setter steps</dfn>, which take the host interface instance, IDL attribute name, content attribute name, and string value, and must return nothing.</li>
</ul>

<p>For every IDL attribute <var>idlAttribute</var> defined in <code>ARIAMixin</code>, on getting, it must perform the following steps:</p>

<ol>
<li><p>Let <var>contentAttribute</var> be the ARIA content attribute determined by looking up <var>idlAttribute</var> in the ARIA Attribute Correspondence table.</p></li>

<li><p>Return the result of running the <a><code>ARIAMixin</code> getter steps</a>, given this, <var>idlAttribute</var>, and <var>contentAttribute</var>.</p></li>
</ol>

<p>Similarly, on setting, it must perform the following steps:</p>

<ol>
<li><p>Let <var>contentAttribute</var> be the ARIA content attribute determined by looking up <var>idlAttribute</var> in the ARIA Attribute Correspondence table.</p></li>

<li><p>Run the <a><code>ARIAMixin</code> setter steps</a>, given this, <var>idlAttribute</var>, <var>contentAttribute</var>, and the given value.</p></li>
</ol>

<p class="note">This very general framework is motivated by the desire for different host interfaces, such as <code>Element</code> and <code>ElementInternals</code>, to give these IDL attributes different behaviors. The alternative is requiring each host interface to duplicate the IDL attributes independently, so that they can specify independent behaviors, but that comes with a high risk of them getting out of sync.</p>
</section>

<section id="accessibilityroleandproperties-correspondence" class="normative" data-dfn-for="ARIAMixin" data-link-for="ARIAMixin">
<h2>ARIA Attribute Correspondence</h2>
<p>The following table provides a correspondence between IDL attribute names and content attribute names, for use by <code>ARIAMixin</code>.</p>

<table>
<tr><th>IDL Attribute</th><th>Reflected ARIA Content Attribute</th></tr>
<tr><td><dfn>role</dfn></td><td><a href="#introrole">role</a></td></tr>
<!-- <tr><td><dfn>ariaActiveDescendantElement</dfn></td><td><pref>aria-activedescendant</pref></td></tr> -->
<tr><td><dfn>ariaAtomic</dfn></td><td><pref>aria-atomic</pref></td></tr>
<tr><td><dfn>ariaAutoComplete</dfn></td><td><pref>aria-autocomplete</pref></td></tr>
<tr><td><dfn>ariaBusy</dfn></td><td><sref>aria-busy</sref></td></tr>
<tr><td><dfn>ariaChecked</dfn></td><td><sref>aria-checked</sref></td></tr>
<tr><td><dfn>ariaColCount</dfn></td><td><pref>aria-colcount</pref></td></tr>
<tr><td><dfn>ariaColIndex</dfn></td><td><pref>aria-colindex</pref></td></tr>
<tr><td><dfn>ariaColIndexText</dfn></td><td><pref>aria-colindextext</pref></td></tr>
<tr><td><dfn>ariaColSpan</dfn></td><td><pref>aria-colspan</pref></td></tr>
<!-- <tr><td><dfn>ariaControlsElements</dfn></td><td><pref>aria-controls</pref></td></tr> -->
<tr><td><dfn>ariaCurrent</dfn></td><td><sref>aria-current</sref></td></tr>
<!-- <tr><td><dfn>ariaDescribedByElements</dfn></td><td><pref>aria-describedby</pref></td></tr> -->
<tr><td><dfn>ariaDescription</dfn></td><td><pref>aria-description</pref></td></tr>
<!-- <tr><td><dfn>ariaDetailsElements</dfn></td><td><pref>aria-details</pref></td></tr> -->
<tr><td><dfn>ariaDisabled</dfn></td><td><sref>aria-disabled</sref></td></tr>
<!-- <tr><td><dfn>ariaErrorMessageElement</dfn></td><td><pref>aria-errormessage</pref></td></tr> -->
<tr><td><dfn>ariaExpanded</dfn></td><td><sref>aria-expanded</sref></td></tr>
<!-- <tr><td><dfn>ariaFlowToElements</dfn></td><td><pref>aria-flowto</pref></td></tr> -->
<tr><td><dfn>ariaHasPopup</dfn></td><td><pref>aria-haspopup</pref></td></tr>
<tr><td><dfn>ariaHidden</dfn></td><td><sref>aria-hidden</sref></td></tr>
<tr><td><dfn>ariaInvalid</dfn></td><td><sref>aria-invalid</sref></td></tr>
<tr><td><dfn>ariaKeyShortcuts</dfn></td><td><pref>aria-keyshortcuts</pref></td></tr>
<tr><td><dfn>ariaLabel</dfn></td><td><pref>aria-label</pref></td></tr>
<!-- <tr><td><dfn>ariaLabelledByElements</dfn></td><td><pref>aria-labelledby</pref></td></tr> -->
<tr><td><dfn>ariaLevel</dfn></td><td><pref>aria-level</pref></td></tr>
<tr><td><dfn>ariaLive</dfn></td><td><pref>aria-live</pref></td></tr>
<tr><td><dfn>ariaModal</dfn></td><td><pref>aria-modal</pref></td></tr>
<tr><td><dfn>ariaMultiLine</dfn></td><td><pref>aria-multiline</pref></td></tr>
<tr><td><dfn>ariaMultiSelectable</dfn></td><td><pref>aria-multiselectable</pref></td></tr>
<tr><td><dfn>ariaOrientation</dfn></td><td><pref>aria-orientation</pref></td></tr>
<!-- <tr><td><dfn>ariaOwnsElements</dfn></td><td><pref>aria-owns</pref></td></tr> -->
<tr><td><dfn>ariaPlaceholder</dfn></td><td><pref>aria-placeholder</pref></td></tr>
<tr><td><dfn>ariaPosInSet</dfn></td><td><pref>aria-posinset</pref></td></tr>
<tr><td><dfn>ariaPressed</dfn></td><td><sref>aria-pressed</sref></td></tr>
<tr><td><dfn>ariaReadOnly</dfn></td><td><pref>aria-readonly</pref></td></tr>
<!-- <tr><td><dfn>ariaRelevant</dfn></td><td><pref>aria-relevant</pref></td></tr> -->
<tr><td><dfn>ariaRequired</dfn></td><td><pref>aria-required</pref></td></tr>
<tr><td><dfn>ariaRoleDescription</dfn></td><td><pref>aria-roledescription</pref></td></tr>
<tr><td><dfn>ariaRowCount</dfn></td><td><pref>aria-rowcount</pref></td></tr>
<tr><td><dfn>ariaRowIndex</dfn></td><td><pref>aria-rowindex</pref></td></tr>
<tr><td><dfn>ariaRowIndexText</dfn></td><td><pref>aria-rowindextext</pref></td></tr>
<tr><td><dfn>ariaRowSpan</dfn></td><td><pref>aria-rowspan</pref></td></tr>
<tr><td><dfn>ariaSelected</dfn></td><td><sref>aria-selected</sref></td></tr>
<tr><td><dfn>ariaSetSize</dfn></td><td><pref>aria-setsize</pref></td></tr>
<tr><td><dfn>ariaSort</dfn></td><td><pref>aria-sort</pref></td></tr>
<tr><td><dfn>ariaValueMax</dfn></td><td><pref>aria-valuemax</pref></td></tr>
<tr><td><dfn>ariaValueMin</dfn></td><td><pref>aria-valuemin</pref></td></tr>
<tr><td><dfn>ariaValueNow</dfn></td><td><pref>aria-valuenow</pref></td></tr>
<tr><td><dfn>ariaValueText</dfn></td><td><pref>aria-valuetext</pref></td></tr>
</table>
<p class="note">Note: Attributes <pref>aria-dropeffect</pref> and <sref>aria-grabbed</sref> were deprecated in ARIA 1.1 and do not have corresponding IDL attributes.</p>

<section class="informative" id="idl_attr_disambiguation">
<h3>Disambiguation Pattern</h3>
<p>Though specification authors may make exceptions to this pattern, the following rules were used to disambiguate names and case of the IDL attributes listed above.</p>
Expand All @@ -12893,6 +12914,24 @@ <h3>IDL Attribute Name Notes or Exceptions</h3>
</section>
</section>

<section id="idl_element">
<h2><code>ARIAMixin</code> Mixed in to <code>Element</code></h2>

<p>User agents MUST include <code>ARIAMixin</code> on <code>Element</code>:</p>

<pre class="idl">
Element includes ARIAMixin;
</pre>

<p>For <code>Element</code>:</p>
<ul>
<li><p>The <a><code>ARIAMixin</code> getter steps</a> given <var>element</var>, <var>idlAttribute</var>, and <var>contentAttribute</var> are to return the result of the getter algorithm for <var>idlAttribute</var> <a href="https://html.spec.whatwg.org/multipage/common-dom-interfaces.html#reflect">reflecting</a> <var>contentAttribute</var> on <var>element</var>.</p></li>
<li><p>The <a><code>ARIAMixin</code> setter steps</a> given <var>element</var>, <var>idlAttribute</var>, <var>contentAttribute</var>, and <var>value</var> are to perform the setter algorithm for <var>idlAttribute</var> <a href="https://html.spec.whatwg.org/multipage/common-dom-interfaces.html#reflect">reflecting</a> <var>contentAttribute</var> on <var>element</var>, given <var>value</var>.</p></li>
</ul>

<p class="note">In practice, this means that, e.g., the <code>role</code> IDL on <code>Element</code> reflects the <code>role</code> content attribute; the <code>ariaValueMin</code> IDL attribute reflects the <code>aria-valuemin</code> content attribute; etc.</p>
</section>

<section class="informative" id="idl_example_usage">
<h2>Example IDL Attribute Usage</h2>
<p>The primary purpose of ARIA IDL attribute reflection is to ease JavaScript-based manipulation of values. The following examples demonstrate its usage.</p>
Expand Down

0 comments on commit c171297

Please sign in to comment.