Table of Contents
- Phase 1
- Phase 2
- Phase 3
- Open questions
- Which ARIA relationship properties should be exposed as element references and under what names?
- How do we attach a virtual
AccessibleNode
subtree? - How does the virtual
AccessibleNode
subtree interact with the DOM tree? - Can virtual
AccessibleNode
s be used in relationships with DOM elements? - Do we need a new API for collection types?
- Why does a
ShadowRoot
need anaccessibleNode
for default semantics?
Setting ARIA properties on non-Custom Elements should just be ARIA. We should just make ARIA reflect in IDL.
el.ariaLabel = "banana";
el.ariaHidden = true; // auto-converts to "true" since this is a string attribute
el.role = "button"; // no validation, this is just a string
el.ariaLabelledby = "an-idref"; // not an element ref here
Rather than add these directly to the Element interface, we propose this be implemented as a mixin
interface:
interface mixin ARIAProperties {
[Reflect] [Unscopable] attribute DOMString? ariaActiveDescendant;
[Unscopable] attribute Element? ariaActiveDescendantElement;
[Reflect] [Unscopable] attribute boolean? ariaAtomic;
[Reflect] [Unscopable] attribute DOMString? ariaAutocomplete;
[Reflect] [Unscopable] attribute boolean? ariaBusy;
[Reflect] [Unscopable] attribute DOMString? ariaChecked;
[Reflect] [Unscopable] attribute short? ariaColCount;
// ...
[Reflect] [Unscopable] attribute DOMString? role;
}
Element includes ARIAProperties;
Other DOM relationships like htmlFor
suffer the same issues as the ARIA relationships regarding ergonomics and Shadow DOM.
We propose that we have a common pattern for all non-tree relationships (including htmlFor
):
el.htmlFor = 'id-for-my-input';
el.htmlForElement = myInput; // overrides htmlFor
myCustomInput.ariaActiveDescendant = 'id-for-my-label';
myCustomInput.ariaActiveDescendantElement = myLabel; // overrides ariaActiveDescendant
myCustomInput.ariaOwns = 'id-for-autocomplete-1';
myCustomInput.ariaOwnsElements = [autocomplete1, autocomplete2]; // overrides ariaOwns
All the ARIA relationship element properties would also be a part of the ARIAProperties
mixin.
When using a property which may be set either via an IDREF or IDREF list string or via an element reference or list of elements, the element reference should take precedence.
For example, if both ariaLabelledBy
and ariaLabelledByElements
were set to refer to different non-null values,
then ariaLabelledBy
should be ignored in favour of ariaLabelledByElements
.
If ariaLabelledByElements
was explicitly set to null
, or an empty list,
or never set, then ariaLabelledBy
should be used.
Instead of attaching event listeners to the AccessibleNode
object, we make the "accessible" events available to Elements.
el.addEventListener('accessibleincrement', function() {
el.value += 1;
});
el.addEventListener('accessibledecrement', function() {
el.value -= 1;
});
We would need a way to prompt in an appropriate and timely manner for user permission to listen for assistive technology events.
// An AccessibleNode represents a virtual accessible node.
interface AccessibleNode {};
AccessibleNode includes ARIAProperties;
interface AccessibleRoot : AccessibleNode {}; // needed?
- Calling
attachAccessibleRoot()
causes anAccessibleRoot
to be associated with aNode
.- The
AccessibleRoot
forms the root of a virtual accessibility tree. - The Node's DOM children are implicitly ignored for accessibility once an
AccessibleRoot
is attached - there is no mixing of DOM children and virtual accessible nodes.
- The
- Like
ShadowRoot
, an element may only have one associatedAccessibleRoot
. - Only
AccessibleNode
s may haveAccessibleNodes
as children, andAccessibleNode
s may only haveAccessibleNode
s as children.
// Implementing a canvas-based spreadsheet's semantics
canvas.attachAccessibleRoot();
let table = canvas.accessibleRoot.appendChild(new AccessibleNode());
table.role = 'table';
table.ariaColCount = 10;
table.ariaRowcount = 100;
let headerRow = table.appendChild(new AccessibleNode());
headerRow.role = 'row';
headerRow.ariaRowindex = 0;
// etc. etc.
We would add an accessibleNode
property on to the ShadowRoot
interface,
which would allow setting default semantics for the host node.
class HowToCheckbox extends HTMLElement {
constructor() {
super();
this.attachShadow({mode: 'open'});
this.shadowRoot.appendChild(template.content.cloneNode(true));
// The default role of the host node should be 'checkbox'.
this.shadowRoot.accessibleNode = 'checkbox';
}
// ...
}
window.customElements.define('howto-checkbox', HowToCheckbox);
<!-- ARIA role overrides AccessibleRoot role -->
<!-- If an author removes the ARIA role, the computed role reverts to "checkbox". -->
<howto-checkbox role="radio"></howto-checkbox>
- Initial idea: begin only with
aria-labelledby
,aria-describedby
andaria-activedescendant
, and then assess.
- A "strawman" API is proposed above, but are there other proposals?
- Can DOM Elements be mixed in to the virtual subtree, like slots in a Shadow tree?
- Simplest proposal: no, once a virtual subtree is attached, it overrides all DOM children of the host Element.
- To be consistent with not mixing the two trees, perhaps not?
- If
AccessibleNode
is primarily intended for building virtual accessibility trees, are we building a kind of virtual accessibility tree on theShadowRoot
? IsAccessibleNode
a node or a bag of properties in this case? - Alternative: define accessible properties directly on
ShadowRoot
using the ARIA vocabulary instead.
Note: this comment refers to an earlier revision
@ aria-* and @ role reflected in IDL on Element is fine with me, but that should just be part of an ARIA or DOM spec update.
However, I'm not convinced that reflected ARIA attrs should replace the existing Phase 1's Element.accessibleNode. Also, I'd prefer it not use the aria-prefixed property on accessibleNode because a) It seems to limit AOM to existing ARIA attrs, and b) Many of these pseudo-reflected relationships may be confusing to authors.
The code samples above are not reflected IDL, but a unique hybrid of reflection, inference, and validation. For example, I find this very confusing (quoting from above):
Doesn't this preclude the intended use of AOM Phase 1 to support relationships without IDREF, including across shadow root boundaries?
ARIA was, to some degree, a declarative workaround for the lack of a scripted interface into the browser's accessibility tree. I expect that trying to re-map declarative ARIA into a JavaScript API will be full of challenges. String-only reflection in IDL is fine (I would support this in the ARIA spec), but I would not want to design a JavaScript API that copies ARIA verbatim.