- From: Daniel Freedman <dfreedm@google.com>
- Date: Thu, 28 Aug 2014 15:13:40 -0700
- To: Domenic Denicola <domenic@domenicdenicola.com>
- Cc: public-webapps <public-webapps@w3.org>
- Message-ID: <CAAUAVAj_-wEJcehmubU8vRTasE6ZE4dkNmQ3V-ka8ULUCQ1oNA@mail.gmail.com>
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