9.3 Presentational Roles Conflict Resolution does not consider custom element use cases
aleventhal opened this issue · 27 comments
Describe your concern
It's natural to provide ARIA properties on a custom element and then have the custom element implementation copy that property to a descendant. For example, aria-label, aria-description or aria-placeholder could be provided by the author on the custom element. The custom element would then copy the ARIA properties to the actual input element in its subtree, and it could then place role="none" on the custom element to avoid 1) Having an extra element in the a11y tree with duplicate properties and 2) Using a name on the custom element which likely has a generic role -- name on generic is prohibited.
Currently the role="none" (or role="presentation") on the custom element is ignored because we are afraid of losing the semantics. However, it seems like a reasonable use case to me. I don't think custom elements should get their role="none" markup ignored when used with aria-foo properties. It should still ignore role="none" if it has a tabindex.
Link to the version of the specification or documentation you were looking at at.
Link to documentation:
https://w3c.github.io/aria/#conflict_resolution_presentation_none
Does the issue exists in the editors draft (the editors draft is the most recent draft of the specification)?
Yes
UPDATE: please see also WICG/webcomponents#1073, to make role="none" the default role for custom elements, except when there is aria-owns or aria-live present, or it is focusable. This is issue is only about allowing role="none" on custom elements at all.
Preemptively adding agenda to this so we can talk about it outside of triage
I don't think I can make this week's meeting. Here is the harmful sentence in the spec:
"If an element has global WAI-ARIA states or properties, user agents MUST ignore the none/presentation role and instead expose the element's implicit role."
Basically, when there's a custom element, I want the "MUST ignore" clause to be invalidated, because it's natural for js libraries to use this (Material makes use of this technique). The js copies the ARIA attributes to an element inside of the shadow root. I want the js to then apply role="none" to the custom element, and for the UA to support that.
I spend a lot of time writing components and helping developers fix their components, and personally I would say this is author error.
I would like to advocate for a role for custom components so we can choose to handle those separately, rather than overloading an existing role.
Does this align with https://github.com/WICG/webcomponents/blob/gh-pages/proposals/reference-target-explainer.md wherein an element author has more finite control over the elements receiving the aria values?
Discussed in ARIA working group meeting on Aug 8: https://www.w3.org/2024/08/08-aria-minutes#t05
@spectranaut Can we put this on the agenda again for this week? I'm back from vacation.
@aleventhal how do you see this intersecting with the planned work around https://github.com/WICG/webcomponents/blob/gh-pages/proposals/reference-target-explainer.md We're getting close to a testable implementation via https://chromium-review.googlesource.com/c/chromium/src/+/5615615 and https://chromium-review.googlesource.com/c/chromium/src/+/5739315 thanks to @behowell and @dandclark
@Westbrook Unless the author set role=none on the custom element, it wouldn't have any effect.
I don't see the author doing that and also using an element relation to point inside of the shadow root via reference target, because if the custom element is copying the ARIA into elements inside of the shadow root, then those relations already don't need to cross-shadow root solution, as they are both originating and targeting elements inside of the shadow root.
In that case, I'm pretty sure that I'm misunderstanding your use case. Would you be able to share a more concrete example?
Example:
<my-weird-checkbox aria-label="I like cats" aria-description="Think deeply about your relationship with cats">
...
In a constuctor or init code:
- The aria-label and aria-description are copied to an inner
<div role=checkbox>
this.role = 'none'; // Remove the original custom element from the a11y tree.
If the browser follows current rules, it must ignore the role=none and keep the custom element in the tree, thus causing 2 nodes to have the same label and description. We had that rule because nobody could think of a reason that you would need global ARIA attributes and role=none on the same element. I'd like to alter the rule now that we see a reason that authors do it.
In that case, is it better for the author for the browser to ignore the combination of role="none" aria-label="..."
on the assumption that they pass the value down for themselves or to discuss expanding Reference Target to manage absolute attributes as well, so that the author wouldn't need to manually pass those values?
I'm no browser implementor, but it would seem that whatever allows the label in this example to be passed through:
<label for="x-checkbox">I'm a checkbox</label>
<x-checkbox id="x-checkbox">
<template
shadowrootmode="open"
shadowrootreferencetarget="real-input"
>
<input type="checkbox" id="real-input">
</template>
</x-checkbox>
Could/should pass through the same when the code was:
<x-checkbox aria-label="I'm a checkbox">
<template
shadowrootmode="open"
shadowrootreferencetarget="real-input"
>
<input type="checkbox" id="real-input">
</template>
</x-checkbox>
I'm not sure — we can study that. Is there any reason that we can't do what I propose as a solution for existing content that we have now? It wouldn't seem to invalidate other future solutions.
Put another way, we only didn't allow role="none" to ablate nodes from the tree when they had other ARIA properties, because we couldn't imagine a reason. Now that we can imagine a reason, this rule is doing harm and I'd like to remove the rule.
This also seems misleading if I explicitly set a role on the host element and the browser doesn't respect that.
It would be nice to allow the user to apply these attributes and allow us to map them to the appropriate internal shadow DOM elements. We have many teams that don't understand custom elements, so, rather than use our APIs, add their own aria
attributes. Although this isn't a true replacement for the "reference targeting" that @Westbrook was referring to, it would be a nice safety net to provide a good user experience.
Discussed in today's ARIA working group meeting: https://www.w3.org/2024/08/15-aria-minutes.html#t05
In that aria-label
and aria-description
, et al. are not reference attributes, they won't be applied via Reference Target in the currently discussed form. If role="none"
, I don't see much harm in my experience in removing an element from the AT and allowing it's custom implementation do to what it will with the values applied to them. There's certainly some author knowledge required around aria-label
reflected to ariaLabel
, etc. but if you're already doing the work to role="none"
hopefully you'll be covering all of your bases for the rest of the functionality.
However, I do think that there is no great difference between an element getting labelled with aria-label
and getting labelled with aria-labelledby
and think that this should be handled in future iterations of Reference Target. To start that conversation, I've opened WICG/webcomponents#1068, which posits an even larger expansion of Reference Target to start, so that when it gets whittled down a bit we're likely to still get coverage for common sense items like those referenced in this issue.
Is role="custom" (applied with some formal grammar mapping rules to avoid misuse) completely off the negotiation table?
I remember there was an old idea in the ARIA group (at 1.0 times) to allow custom roles (or role customization) using e.g. JSON notation. But this caused a can-of-worms discussion and the idea was abandoned.
In this sense, for a checkbox with additional properties authors could write
<div role="custom checkbox">
with attached JS fetch handler for JSON data that contains ARIA and custom attribute value pairs. Of course screen readers must be prepped to support this.
@aleventhal to summarise the proposal (unless I am over simplifying). We would add to the last bullet of the presentational roles conflict resolution section:
- If an element has global WAI-ARIA states or properties, user agents MUST ignore the none/presentation role and instead expose the element's implicit role. However, if an element has only non-global, role-specific WAI-ARIA states or properties, the element MUST NOT be exposed unless the presentational role is inherited and an explicit non-presentational role is applied.
to become something like
- If an element has global WAI-ARIA states or properties, user agents MUST ignore the none/presentation role and instead expose the element's implicit role unless the element is a custom element and has an explicit role=none/presentation. However, if an element has only non-global, role-specific WAI-ARIA states or properties, the element MUST NOT be exposed unless the presentational role is inherited and an explicit non-presentational role is applied.
Yes James, that sounds good to me. Do we want to add some non-normative text explaining why the exception exists?
I think a note for this would be a good addition. I just want to clarify what we are discussing as a possibility. We'd obviously want to make sure that the other browser vendors are on board too.
We should also have a default role of none for custom elements, unless they are focusable, have aria-owns, or aria-live.
See WICG/webcomponents#1073.
This seemed to get general support at TPAC. I have a couple of commits in Chromium waiting on official WG consensus.
looking through the global html attributes that could be used on a custom element, seems they'd mostly fit in to the 'focusable' (e.g., tabindex, autofocus) category, or already have minimum role expectations for them (popover, draggable).
but what about title
? not asking because i'm at all a fan of the attribute - but it's always been the odd one out with the presentational role conflict resolution, since it only ever outlined what to do for instances of an element being focusable, or having a global ARIA attribute, but no mention what to do with global (HTML) host language attributes.
my guess is that if it was ignored, it'd likely be information that people didn't have great access to in the first place, so maybe nothing lost? And for the instances of where attributes were being used for passing down into the internals of the custom element, it'd maybe be fine anyway. just probably worth making sure it's understood / called out so other people also don't wonder what is supposed to happen.
CLs for Chromium/Blink:
https://chromium-review.googlesource.com/c/chromium/src/+/5894644 (allow role="none" as in this issue)
https://chromium-review.googlesource.com/c/chromium/src/+/5894749 (default role of "none" as in WICG/webcomponents#1073)
What do we do if custom elements do try to EXTEND base roles? Shouldn't there a base role to be specified? Or should there be aria-roledescription used instead? Can we have this discussion less generic and more concrete example based?
Discussed briefly in today's meeting: https://www.w3.org/2024/10/24-aria-minutes.html#e25e
@smhigley volunteered to open a PR with html-aam changes :)
This isn't just about the original idea to allow role=none on custom elements, I don't think. Now it's also about having custom elements have a default role of none.
We should think about what is the best way to say this so that spec readers will understand it. I'm not sure that the presentational role conflict resolution is the best place. Maybe it needs to be there, but somewhere else as well. maybe it even deserves its own section, and needs HTML-AAM treatment.
As a high level thing in Chrome's prototype implementation, it is more about when to ignore custom elements. As in, "Ignore custom elements in the a11y tree with these exceptions (focus/owns/live)" rather than 1) give it a default role of none, and 2) change when we ignore role=none on custom elements. It probably comes out to the same thing. But, it may actually be worth considering that when to ignore custom elements is easier to understand than giving the conflict resolution section a complex treatment or list of exceptions. Again, we could do both. I'm just not sure readers would expect something so important to just be a set of fractally complex exceptions in the presentational conflict resolution section.
Starting in Chromium 133.0.6852.0 (currently in Canary), you can run Chrome/Edge with the command --enable-blink-features=AccessibilityCustomElementRoleNone. It changes custom elements to use a default role of none, meaning that the custom element will be removed from the a11y tree, with these exceptions:
- is focusable
- has aria-live,
- has aria-owns
- uses element internals to set an ARIA property
- uses an ARIA relation via an element attribute (e.g. myCustomElement.ariaLabelledByElements = [ labelElement ]; )
Since it's a default role, that means it only takes place if the author did not provide their own role for the element.
@smhigley @jnurthen @scottaohara We need to update the HTML-AAM spec for the default role part, and the ARIA presentational roles conflict resolution to even allow role="none" on a custom element in the first place. Does anyone have cycles for it?
If I don't hear any objections, I'll update to "experiment" stage which turns it on when "experimental web platform features" is enabled in chrome://flags.
CC'ing other implementers as well so that they know this is active. @cookiecrook @jcsteh
The changes described in #2383 can now be tested in Chrome Canary 133.0.6876.0 or later by running with the command line parameter --enable-blink-features=AccessibilityCustomElementRoleNone.