Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RfC: API design for aria delegation mechanism #917

Open
dfreedm opened this issue Mar 31, 2021 · 14 comments
Open

RfC: API design for aria delegation mechanism #917

dfreedm opened this issue Mar 31, 2021 · 14 comments

Comments

@dfreedm
Copy link

dfreedm commented Mar 31, 2021

Synopsis

The AOM group has been discussing a "delegation" API to allow for ARIA attributes and properties set on a webcomponent to be forwarded to elements inside of its shadowroot as a simpler solution to the issues raised in WICG/aom#169.
This mechanism will allow users to apply standard best practices for ARIA, and should solve a large margin of accessibility use cases. This API is most suited for one-to-one delegation, but should also work for one-to-many setups. There is no mechanism for directly relating two elements in different shadowroots together, but this will still be possible manually with the element reflection API.

The AOM group considered two very similar API proposals, ElementInternals::delegate and ShadowRoot::delegate. Both have the same syntax, but the group did not agree strongly on whether ElementInternals or ShadowRoot was the "better" fit.

Example

The my-input element delegates the aria-label and aria-describedby attributes, and ariaLabel and ariaDescribedByElements properties to an internal input element.

Users of my-input can use either the attributes or properties as expected, and the internal input element will announce instead of my-input.

<span id="description">Description</span>
<!-- announces nothing for the screen reader -->
<my-input aria-label="Label" aria-describedby="description">
  <!-- shadow root -->
  <!-- announces with label "Label" and description "Description" -->
  <input>
  <!-- /shadow root -->
</my-input>
class MyInput extends HTMLElement {
  constructor() {
    super();
    const input = document.createElement('input');
    this.shadowRoot.appendChild(input);
    // Option 1
    this.shadowRoot.delegate({ariaLabel: input, ariaDescribedByElements: input});
    // Option 2
   const internals = this.attachInternals();
   internals.delegate({ariaLabel: input, ariaDescribedByElements: input});
  }
}
@dfreedm
Copy link
Author

dfreedm commented Mar 31, 2021

@rniwa
Copy link
Collaborator

rniwa commented Apr 6, 2021

During F2F today, we discussed an alternative where we'd add a boolean something like delegatesLabel like we have for delegatesFocus and introduce a new content attribute like autolabel (we can bikeshed this). This has an advantage that it works with declarative Shadow DOM as well, and it is consistent with delegatesFocus. It also works better with React-like DOM updating model where you may not necessarily have access to a DOM node right where you're creating / declaring it.

@dfreedm
Copy link
Author

dfreedm commented Apr 20, 2021

@annevk
Copy link
Collaborator

annevk commented Apr 20, 2021

FWIW, delegatesLabel is #916.

@joanmarie
Copy link

Is the plan for there to be a whole series of per-property delegatesFoo? (e.g. delegatesHasPopup, delegatesExpanded, delegatesSetSize, delegatesDescription, etc.)?

@leobalter
Copy link

leobalter commented Jan 13, 2022

I'm assigning this work to myself as discussed today at the AOM meeting. I don't have write permissions to do this formally in this github org, but this comment might be good enough for now.

The general understanding is that we have consensus for this and the next step is drafting the specs.

Following this I should work on #916.

Thanks!

@domenic
Copy link
Collaborator

domenic commented Jan 13, 2022

To ensure I understand, this proposal gives no new capabilities; it just makes it easier to coordinate instead of manually synchronizing someDescendant.ariaLabel with elementInternals.ariaLabel?

@leobalter
Copy link

My understanding is this proposal allows usage of web components to have aria attributes in their top layers that are then delegated to their encapsulated shadow dom within the discretion of their constructor. For this it seems like a new capability but I might be corrected.

This is useful for resolving aria attributions top down to web components, but the main goal to achieve is the full cross-root aria challenge. For that, #916 might be the next stone.

@domenic
Copy link
Collaborator

domenic commented Jan 15, 2022

I believe that is already possible using code such as the following (referring to the example in the OP):

class MyInput extends HTMLElement {
  static observedAttributes = ["aria-label"];
  #input;
  
  constructor() {
    super();
    this.#input = document.createElement('input');
    this.shadowRoot.appendChild(this.#input);
    
    this.#input.ariaLabel = this.ariaLabel;
  }
  
  attributeChangedCallback(name, newValue, oldValue) {
    if (name === "aria-label") {
      this.#input.ariaLabel = this.ariaLabel;
    }
  }
}

Can you spot anything that this proposal would enable that code like the above would not? It would be really helpful to understand the scope of the proposal to get a clear answer.

@justinfagnani
Copy link
Contributor

I thought the main advantage was the attribute not applying to the host element when it's delegated. For instance when delegating aria-label you want readers to know that it applies to the input, not both the input and the host. My understanding is also that current workarounds include copying the attribute over and removing it from the host, but that introduces other problems.

Is that correct @dfreedm ?

@leobalter
Copy link

I'm working on a document on how this and 916 applies to my current use cases. I might be missing a point with this current solution vs what @domenic pointed out. I need time to investigate this and I hope to come in with a good conclusion on the following steps next week.

@asyncLiz
Copy link

I thought the main advantage was the attribute not applying to the host element when it's delegated. For instance when delegating aria-label you want readers to know that it applies to the input, not both the input and the host. My understanding is also that current workarounds include copying the attribute over and removing it from the host, but that introduces other problems.

Is that correct @dfreedm ?

That is correct!

@WickyNilliams
Copy link

WickyNilliams commented Feb 9, 2022

@domenic your example works with aria-label, since its value is the literal label text, but wouldn't work with id-based relationships like aria-labelledby or aria-describedby? This proposal seems to open up support for the latter, judging by the example in OP

@Westbrook
Copy link
Collaborator

Feels like some of this is closed by https://github.com/WICG/webcomponents/blob/gh-pages/proposals/reference-target-explainer.md but there is deeper nuance that should continue to be discussed in the form of: #1068

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

10 participants