Re: [Custom] Custom elements and ARIA

Why not put the `implicitAria` role on the element's prototype?
That way each instance can override with the attribute in a naive and
natural manner: `el.role = "link"`.

This would necessitate some getter/setter logic for the aria properties to
handle the something like the <details> case with conditional states, but
as long as the custom setter/getters can call the HTMLElement's role
setter/getters, then I think we can keep the deep magic in the UA's
bindings.


On Thu, Aug 28, 2014 at 2:24 PM, Domenic Denicola <
domenic@domenicdenicola.com> wrote:

> Thanks to all for their responses. The fact that I misread a bunch of
> authoring requirements as UA requirements made things a lot more
> complicated than they are in reality.
>
> I updated my ARIA summary [1] and illustrative scenarios [2] to reflect
> the actual spec/browser behavior. And, given the much-easier requirements,
> I was able to draft up a pretty simple solution:
>
> https://gist.github.com/domenic/8ae33f320b856a9aef43
>
> I still need to investigate whether this kind of solution is feasible from
> an implementation perspective, but from an author perspective it seems
> natural and easy to use.
>
> Would love to hear what others think.
>
> [1]: https://gist.github.com/domenic/ae2331ee72b3847ce7f5
> [2]: https://gist.github.com/domenic/bc8a36d9608d65bd7fa9
>
>
> -----Original Message-----
> From: Domenic Denicola [mailto:domenic@domenicdenicola.com]
> Sent: Wednesday, August 27, 2014 19:43
> To: public-webapps
> Subject: [Custom] Custom elements and ARIA
>
> TL;DR: we (Google) are trying to explain the platform with custom elements
> [1], and noticed they can't do ARIA as well as native elements. We would
> like to prototype a solution, ideally as a standardized API that we can let
> authors use too. (If that doesn't work, then we can instead add a
> non-web-exposed API that we can use inside Chrome, but that would be a
> shame.) A succinct statement of the problem is that we need some way to
> explain [3]. The rest of this mail explains the problem in great depth in
> the hopes other people are interested in designing a solution with me.
>
> Also, in the course of figuring all this out, I put together an intro to
> the relevant aspects of ARIA, which you might find useful, at [2].
>
> ## The problem
>
> Right now, custom elements can manually add ARIA roles and stoperties (=
> states or properties) to themselves, by setting attributes on themselves.
> In practice, this kind of allows them to have default ARIA roles and
> stoperties, but they are fragile and exposed in a way that is incongruous
> with the capabilities of native elements in this regard.
>
> For example, if we were to implement `<hr>` as a custom element, we would
> attempt to give it the separator role by doing `this.setAttribute("role",
> "separator")` in the `createdCallback`. However, if the author then did
> `document.querySelector("custom-hr").setAttribute("role", "menuitem")`,
> assistive technology would reflect our `<custom-hr>` as a menu item, and
> not as a separator. So **unlike native elements, custom elements cannot
> have non-overridable semantics**.
>
> Furthermore, even if the author wasn't overriding the role attribute,
> there would still be a difference between `<hr>` and `<custom-hr>`. Namely,
> `document.querySelector("hr").getAttribute("role") === null`, whereas
> `document.querySelector("custom-hr").getAttribute("role") === "separator"`.
> So **unlike native elements, custom elements cannot have default ARIA roles
> or stoperties without them being reflected in the DOM**.
>
> As another example, imagine trying to implement `<button>` as a custom
> element. To enforce the restriction to a role of either `button` or
> `menuitem`, the custom element implementation would need to use its
> `attributeChangedCallback` to revert changes that go outside those
> possibilities. And that of course only occurs at the end of the microtask,
> so in the meantime screen-readers are giving their users bad information.
> And even then, the experience of the attribute value being reverted for the
> custom element is not the same as that for a native element, where the
> attribute value stays the same but the true ARIA role as reflected to
> screenreaders remains `button`. So: **unlike native elements, custom
> elements cannot robustly restrict their ARIA roles to certain values**.
>
> Finally, consider how `<details>` synchronizes `aria-expanded` with the
> `open` attribute. To implement this with custom elements, you would use the
> `attributeChangedCallback` to set an `aria-expanded` attribute. But again,
> the author could change it via `setAttribute`, causing it to be
> out-of-sync. The takeaway here is that **unlike native elements, custom
> elements cannot reserve the management of certain stoperties for
> themselves**.
>
> In the end, trying to manage one's ARIA state HTML attributes is fragile,
> and lacks the conceptual stratification and the resultant power of the
> internal state/mutable HTML attribute approach used by native elements. [3]
> illustrates more drastically the differences between the internal state and
> the HTML elements in many representative cases.
>
> ## Discussion
>
> In my own musings, I came up with a few solutions [4], but they are pretty
> icky to program against. There are a few tough issues that emerge, e.g.
>
> - Do we allow programmatic changing of *all* elements roles/stoperties,
> e.g. via a new API `element.aria.role = "whatever"`, or do we want some
> kind of model that reserves that power for the author of the element code?
> The former allows bad things like a <hr> with role menuitem, but the latter
> makes for tricky programming.
>
> - If an element wants to manage some aspect of its ARIA state itself, e.g.
> restrict its role, how does that impact the rest of its ARIA stuff? E.g.,
> how can I signal that I want to manage aria-expanded, ignoring any
> attribute-setting that goes on, while at the same time allowing the author
> to mess with aria-hidden at will? Or even more complex, how can I signal
> that I want to have a default way of calculating aria-level, but if the
> author sets it, their value overrides it (until they removeAttribute)?
>
> - Trying for a declarative solution, e.g. `"aria-expanded": function () {
> return this.hasAttribute("open"); }` gets you 90% of the way there, but you
> need some way of triggering an "ARIA recalc." E.g. <details> would trigger
> an ARIA recalc when its open="" attribute changes, and h1 would trigger an
> ARIA recalc whenever its position within the document changes (because that
> potentially affects outline level), and input would trigger an ARIA recalc
> under any situation where a <datalist> could become associated with it. If
> you accept this premise, then who has the power to trigger an ARIA recalc?
> Who has the responsibility?
>
> I would welcome anyone else's ideas on solutions. The cases that need to
> be addressed are summed up, somewhat representatively, in [3]. If nobody is
> interested I'll probably just evolve my existing kinda-icky solutions, and
> code one of them into Chrome as a non-web-exposed API (or maybe expose it
> behind a flag).
>
> [1]: https://github.com/dglazkov/html-as-custom-elements
> [2]: https://gist.github.com/domenic/ae2331ee72b3847ce7f5
> [3]: https://gist.github.com/domenic/bc8a36d9608d65bd7fa9
> [4]: https://gist.github.com/domenic/4ddde9bdcb673c48f237
>
>

Received on Thursday, 28 August 2014 22:14:28 UTC