w3c / aria

Accessible Rich Internet Applications (WAI-ARIA)
https://w3c.github.io/aria/
Other
639 stars 123 forks source link

Secondary actions on items in composite widget roles #1440

Open smhigley opened 3 years ago

smhigley commented 3 years ago

I've been repeatedly running into a difficulty between a relatively common app UI pattern and the required owned elements part of the ARIA spec. The problem is specifically with secondary actions with composite interactive widget roles. I'm using "secondary action" to refer to cases where the child of the composite widget role (e.g. tab, treeitem, option, etc.) performs a primary action that makes sense for its role, but then also has secondary actions like edit/delete/etc., exposed through an associated button.

Here are some examples of UI that have this pattern:

  1. Close buttons in tabs (probably the most familiar example): the VS Code tab list of open files, the selected tab has a visible close button
  2. A menu of recently opened files, where each file has share, favorite, and more actions buttons: A single item from within a menu or other interactive list; the item has an icon, a formatted name (Document125) and file location, then at the right there are three icon buttons for share, star, and a kebab menu
  3. A tree of participants in a meeting, where each participant has mute and more actions buttons: A part of the Teams meeting UI, showing only the first meeting participant under the tree section titled "In this meeting". The participant tree item shows a small avatar, a name, and to the right are a mute button and kebab menu
  4. A tree of emails, where each email has flag, complete, and more actions buttons: A screenshot of a series of notifications in two categories, today and older, similar to Outlook emails. Each notification has an avatar, a formatted title like "Theo assigned you a task", document name, and time, and three buttons in the top right corner for flag, a check mark, and a kebab menu.

Context menu approach

A solution we've used in the past was to make the visual buttons presentation-only, and duplicate all secondary actions in a context menu. The problem is the context menu wasn't sufficiently discoverable in practice, and sighted users who relied on keyboard navigation (either with or without a screen reader) expected to be able to directly reach the visible buttons.

If a context menu alone were a good approach, this would be covered by #762, but the discoverability problem is enough to make me think there needs to be a pattern for surfacing the secondary action buttons directly.

Nested vs. sibling options

Exposing the buttons directly runs into two spec + support problems:

  1. Putting the secondary action buttons inside the tab/option/treeitem/etc. runs afoul of "Children: presentational" in the spec, and has known support problems.
  2. Putting the secondary actions adjacent to the tab/option/treeitem/etc may or may not violate the "Required Owned Elements" part of the spec, depending on how #1033 falls out.

I did some testing of practical support for nested vs. sibling buttons within composite widgets, with both the working test cases and results tables on this test page. It seems to pretty clearly come down on the side of sibling buttons having better support.

Aside from the test results, I don't personally have much of an opinion on the specific approach used, but I think we have a strong need for explicitly defining some sort of pattern defined for these cases.

scottaohara commented 3 years ago

spitballing here, but i wonder if there couldn't be some sort of special allowances to secondary related controls, as long as they had a programmatic association with the required children - theoretically giving them a reason to be there.

using the tab with a close button example, having those as nested children is weird. but they aren't allowed children of a tablist. but what if there were a special allowance where if, say, the button had an aria-controls association with the tab, then it would be allowed in the tablist? this way, the following would still not be allowed:

<div role=tablist>
  <button>what am i doing here? i think i'm in the wrong house...</button>
  ...
</div>

but the following "would"

<div role=tablist>
  <div role=none class=tab-container>
    <button role=tab id=hi>hi</button>
    <button aria-controls=hi>close</button>
  </div>
  ...
</div>

please, feel free to poke all the holes in this. just first thing that came to mind, and would give aria-controls something else to be useful for.

JAWS-test commented 3 years ago

See: https://github.com/w3c/aria/issues/1385

smhigley commented 3 years ago

@scottaohara I like your idea :). I'm not sure exactly how it'd be defined in spec language, but I'd be in favor of some sort of Allowed Child Elements thing that replaces Required Owned Elements, and has a list of roles + some term for anything associated via aria-controls.

@JAWS-test I saw that issue, and it's definitely helpful to link the two to illustrate that secondary actions is a common issue that many people run in to :). That said, this issue is more about how include buttons that are visually present in the accessibility tree, which wouldn't be solved with an attribute -- specifically non-screen reader use cases like keyboard interaction and voice control, screen reader touch exploration, and expectations of sighted screen reader users. I think the attribute is an interesting idea, but it makes sense to discuss the two separately.

mcking65 commented 3 years ago

If they are children, won't screen readers then have to present the tab or treeitem as a container? When reading via touch or reading cursor, we'd ideally want the action buttons as siblings, hopefully associated siblings so the screen reader can tell you that the button is delte for tabx or for treeitem named x or something like that.

If they are children of the tab or treeitem, they effect accname calc. if they are not children, then we don't have to worry about name calc.

If they are siblings of the item but still inside the composite, the browsers will have to do some fancy footwork to address indexing, i.e., posinset.

I wish I could attend the deep dive. Looking forward to the outcome.

I'm super concerned about screen reader expectations if they are children of the item though.

MelSumner commented 3 years ago

It would be nice to have some sort of clear pattern and standardized role for this sort of thing. As long as we keep it distinct, because I don't want to break linting checks for nested interactive elements.

joanmarie commented 3 years ago

As a screen reader developer, I think that such controls are more naturally/conceptually children of the widget they control; not siblings.

And while I agree with @mcking65 that we need to be concerned about screen reader expectations, I also think we should do some debugging (i.e. in the browsers and where possible the screen readers) to determine why something isn't working as we expect before we conclude a particular approach is the wrong one.

brandonthomas commented 3 years ago

Any update on this @smhigley? We're seeing this in some of our code as well and would love to align where possible.

aleventhal commented 2 years ago

As a data point, the Chrome address bar suggestions and Google search suggestions can have additional actions as you up/down arrow. For example, a Remove (from future suggestions) button and/or "Switch to tab" (if already open). The best way we could find for that case was that the tab key can access the additional buttons for the currently selected listbox option. The text of the option itself provides the keyboard hint so that's discoverable.

smhigley commented 2 years ago

Here's an attempt at somewhat-cohesive notes for discussion on thursday:

Pros and Cons of each approach:

Sibling pros

Sibling cons

Nested approach pros

Nested approach cons

Possible options for handling nested secondary actions and naming:

Outstanding questions:

If we go with nested actions, what do people do in the meantime?

For browser vendors: how hard would it be to use either an aria-actions-like attribute or a per-nested-element attribute to both calculate the parent's accessible name and expose that actions exist?

stes-acc commented 2 years ago

Don't forget the context menu of an item to access item-specific functions.

stes-acc commented 2 years ago

As a data point, the Chrome address bar suggestions and Google search suggestions can have additional actions as you up/down arrow. For example, a Remove (from future suggestions) button and/or "Switch to tab" (if already open). The best way we could find for that case was that the tab key can access the additional buttons for the currently selected listbox option. The text of the option itself provides the keyboard hint so that's discoverable.

Not agree on last sentence. Imagine a tree with additional non-presentational content in nodes where each node reminds you so. Horrible.

aleventhal commented 2 years ago

@stes-acc That's why this bug is important, to find a better way. It's not as bad as you say, if you try it, but that's not related to this issue.

smhigley commented 2 years ago

@stes-acc I haven't forgotten the context menu :). That has been one keyboard mechanism we've tried as a way to give access to what are visually secondary buttons on an item. The problems are:

  1. sighted keyboard users expect to be able to reach the actual visual buttons
  2. context menus aren't all that discoverable to users
stes-acc commented 2 years ago

@stes-acc I haven't forgotten the context menu :). That has been one keyboard mechanism we've tried as a way to give access to what are visually secondary buttons on an item. The problems are:

  1. sighted keyboard users expect to be able to reach the actual visual buttons
  2. context menus aren't all that discoverable to users

Well then MS should better stop context menu support in their UIs? But joking aside, context menus are a valuable redundant fallback for people that a) know (and expect!) them and b) are always keyboard accessible as an alternative if discussions on this topic will lead to nirvana..

BTW, I propose entering into a focused item with F2 (Excel dig into cell approach), Tabbing in between multiple active subitems, Shift+F2 to refocus item and TAB to finally skip the entire thing. In this sense, TAB acts as a free skipping key as before and we have no disruption in expected behaviour.

chlane commented 2 years ago

@stes-acc I like the idea of using F2 to dig into the cell. This aligns with our technique for navigating or editing inside of grid cells (https://www.w3.org/TR/wai-aria-practices-1.1/#gridNav_focus). I can see this working some roles like tab that aren't based on an existing HTML element. @smhigley @stes-acc I agree with both of you. IMO sighted keyboard users should be able to use the visible buttons. But context menus are a valuable fallback as long as users know they are available and how to use them. Regarding nesting vs. siblings, I favor an interaction with siblings in some kind of container as seen with the gridcell. I think we need need to stay aligned with the HTML spec and restrict some roles, like button, from containing interactive content.

devongovett commented 2 years ago

Note that due to https://bugs.webkit.org/show_bug.cgi?id=213953 it is currently impossible to trigger a context menu when using VoiceOver for iOS AFAIK. Hopefully that gets fixed at some point.

cookiecrook commented 2 years ago

@smhigley wrote:

Possible options for handling nested secondary actions and naming: • add an attribute like aria-actions that takes a space-separated list of ids

Apologies for missing this suggestion. I reviewed the issue last week, but didn't see your recent comments before the meeting.

I think aria-actions=IDREFS is a good suggestion. @Alice Boxhall suggested something similar (direct comment link) in the past, in the context of #762. If I understand correctly, this approach could solve the use cases here, and in the other issue.

With one caveat:

Possible options for handling ~nested~ secondary actions and naming

If this refers to DOM nesting, the API shouldn't be limited to nested elements.

The IDREFS should work with any DOM element (nested, siblings, or in a different part of the DOM entirely). This pattern would also allow reflection to element.ariaActionsElements = elementRefs; for local document scope convenience and crossing shadow DOM boundaries, which isn't possible with IDREFS alone. Note: there would be two 's' characters in element.ariaActionsElements as both Actions and Elements are plural.

cookiecrook commented 2 years ago

Also mentioned in the other issue comment, there's a potential to avoid "AT detection" by exposing some mainstream browser UI... Proposals have linked an action trigger to some visual UI element using a clickable DOM element (button, etc), like the following example screen shot.

Screen shot from Gmail showing secondary hover actions Gmail messages table with actions: archive, delete, etc on the first row

But the example buttons in the screen shot aren't displayed at all times; only when a mouse user hovers. So if a web app detected a click on the actioning element when it was still hidden, the sequence could out a user of assistive technology, violating WPDP §2.9.

A possible path forward may be to make this a native HTML feature (e.g. actions not aria-actions) and have it render native UI, such as a sub-menu of actions in the right-click context menu. A user could trigger the action from the DOM element (visible in screen shot), or from the mainstream UI element (e.g. context menu item), or via assistive technology (like VoiceOver's "actions rotor")... The web app author would find it difficult to distinguish the latter two, so an AT user's privacy could be better preserved.

cookiecrook commented 2 years ago

Now that :focus-within is widely available and known, there's probably less risk of a different event sequence. Short of getting a native HTML feature (actions="" which is unlikely IMO) I think aria-actions=IDREFS (with reflected el.ariaActionElements)seems like a reasonable path forward. I'll start shopping the gist around in WebKit circles.

Primary feedback so far is that this shouldn't be limited to specific composite ARIA widgets. That's unnecessarily limiting. A global attribute (with exclusions for the generic role) may be sufficient.

As one example where this might be used outside an ARIA composite widget context, the native <video> element implementations could leverage this pattern to point to its shadow DOM play/pause button and other features. This could be a path forward to implement other custom video players in an accessible manner, too.

smhigley commented 2 years ago

Thanks @cookiecrook! Also great point about <video> and applicability outside composite widget roles.

For anyone following along, I wrote up a more specific proposal for secondary actions and aria-actions here: https://gist.github.com/smhigley/8dbe67f834cc472e3a14bf6b289e6f0c

smhigley commented 2 years ago

Specific proposal to discuss (based on previous discussions & the gist):

Add specific aria-actions attribute with the following requirements:

Authoring requirements for aria-actions:

Accessible name change:

In step 2.F.iii, if the current node has aria-actions and one of the aria-actions ids matches the child node's id, skip steps a-c for this child.

Change to Children: Presentational:

Any node referenced by aria-actions MUST have its semantics exposed when focused, even if within a parent with children presentational: true. For more specifics, I think Scott's proposal here would work well for aria-actions: https://github.com/w3c/aria/issues/1174#issuecomment-1092809526

scottaohara commented 2 years ago

Authors MUST provide a keyboard mechanism to navigate to or directly activate the secondary actions.

This seems like it would require the use of aria-keyshortcuts to identify such keys, unless a more general indicator could be provided. e.g., the Tab key (or Tab + OTHER keys) SHOULD allow for access to the secondary action(s)... sorry if i missed this part of the discussion since i joined late yesterday.

Regarding children presentational, I'll comment in https://github.com/w3c/aria/issues/1174 as these points are related

JAWS-test commented 2 years ago

This seems like it would require the use of aria-keyshortcuts to identify such keys

aria-keyshortcuts would not help in my opinion, because I am only passing the shortcut of the current element, but not of the child elements. Also:

There are applications where I reach the child elements with TAB, in others shortcuts are implemented. I think this needs more thought:

scottaohara commented 2 years ago

aria-keyshortcuts would not help in my opinion,

well, per how it's presently spec'd yes, I can see why you'd say that. But since we're talking about a new feature here, we have to come up with new proposals. One such could be the repurposing of a feature that is already specified to identify keyboard shortcuts to help in identify keyboard shortcuts

Sighted keyboard users would not notice the shortcut.

Yup. But that is also an issue that exists today. Author guidance on how to expose the mechanisms to interact via keyboard need to be made, but regardless of how the keyboard shortcuts are identified and implemented, solving for this problem goes beyond what ARIA likely needs to normatively define.

JAWS-test commented 2 years ago

But since we're talking about a new feature here, we have to come up with new proposals.

I see. Then I agree with that.

Yup. But that is also an issue that exists today

In applications that are compliant with WCAG SC 2.1.1, all controls are usually given focus with TAB. The shortcuts are then used to reach or operate an element more efficiently. However, I do not rely on the shortcut. Secondary actions seem to be different: they don't necessarily get focus with TAB. The shortcuts must therefore be perceptible. This will be difficult, because the shortcuts are probably often not part of the label (like in a menu), because the elements are often labeled with icons.

Author guidance on how to expose the mechanisms to interact via keyboard need to be made ... solving for this problem goes beyond what ARIA likely needs to normatively define.

This would not be an issue for the ARIA specification, but should already be considered. It may be relevant for ARIA Authoring Practices

chlane commented 2 years ago

I agree that a technique to provide visual affordances to let sighted keyboard users know about keyboard commands is needed. I think authors could use something like the "arrow-keys-indicator" below, that is found in our Minimal Data Grid example.

<div id="arrow-keys-indicator" class=" hidden"></div>

smhigley commented 2 years ago

I'm in favor of explicitly mentioning aria-keyshortcuts in the author should statement, e.g.:

If the secondary action is not directly navigable with the keyboard and author provides a keyboard shortcut to directly activate it, that shortcut SHOULD be discoverable through aria-keyshortcuts and follow existing conventions.

As far as specifics go, I like the suggestions thrown out but I think they're out of scope for the ARIA spec and would belong in ARIA Practices.

cookiecrook commented 1 year ago

I've discussed with a dozen or so people inside Apple and out, and everyone seems to agree this doesn't add any more risk of heuristic detection than those items called out in https://github.com/w3ctag/design-principles/issues/293. Also, the edge cases here are much thinner and more difficult to exploit, so I believe the benefits of this new attribute far exceed any risk.

I think it'd be good to move forward with a simple IDREFS-based content attribute (aria-actions="id1 id2 1d3") and element reference IDL reflection:

[CEReactions] attribute FrozenArray<Element>? ariaActionsElements;
smhigley commented 1 year ago

Open question: should we add a sub-section to 4.3 about aria-actions?

scottaohara commented 1 year ago

IMO i think that would be very helpful.

adampage commented 1 year ago

I’m super late to this party, but enthusiastic about the aria-actions proposal. I’ve created a quick markup concept for a “code snippet” pattern using aria-actions to offer a “Copy to clipboard” action via the focusable scrolling region:

https://codepen.io/adampage/pen/PoerwPE

jcsteh commented 1 year ago

Overall, I love this idea. I was considering prototyping something like this a few years ago, but never got around to it. It could make the web a lot nicer on mobile in particular.

* ATs would need to change as well. `<summary>` shows some of the squirrely bits, e.g. with virtual cursor not reaching nested elements

Another thing to keep in mind with nested elements is that they can create some surprising behaviourfor users. Imagine something like this: data:text/html,before<div role="tablist"><div role="tab"><button>Close</button>Fun stuff NVDA + Firefox render the button inside the tab. (Strictly speaking, this violates the spec.) If you press down arrow to move to the tab, what happens when you press enter? It will activate the close button because the cursor lands on that first. But because the presence of the tab is reported as well, a user might not expect that. Arguably, this is just bad authoring: the close button shouldn't be before the label of the tab. However, this kind of thing can and does happen. I'm not suggesting this is a show-stopper, but I thought it worth flagging.

Accessible name change: In step > 2.F.iii, if the current node has aria-actions and one of the aria-actions ids matches the child node's id, skip steps a-c for this child.

The proposal assumes only one level of nesting. If there are multiple levels of nesting, we might end up recursing due to 2h. In that case, the "current node" might not be the node with aria-actions. I think we'd need to look at aria-actions on the "root node". That raises questions about how this affects aria-labelledby traversals, though, because the "root node" in that case might not even be in the subtree we're targeting with aria-labelledby.

Also, there are cases where the author might want some actions to be included in the name. Twitter is a good example, where the author of the tweet, any links, etc. might all be useful "actions". I guess the author could override with aria-labelledby in that case and we wouldn't do any aria-actions processing there.

aleventhal commented 1 year ago

We need an end-to-end strategy that includes working with AT vendors, brainstorming good user experiences, determining priorities, creating examples, and spending the time to drive the project to completion within ATs. We've attempted to do that for aria-details/annotations with some success. Here's a document that came together -- it started as a brainstorming doc, and was circulated until we collected the best ideas and could prioritize them: https://docs.google.com/document/d/1DYrsHDk6Y9071A1fRg8g8NZ_DtGYraX5BcVY-taBzMQ/edit#heading=h.3ouywf2zdx7

lukewarlow commented 10 months ago

Is there anything that can be done to help with progressing the aria-actions proposal? Some of us in openUI are interested in working on native tab UI and secondary actions is currently a big unsolved issue.

brennanyoung commented 9 months ago

Not sure if it fits here, or whether it is handled adequately by aria-details but I just ran into this stackoverflow query about how best to include a countdown timer inside a button.

https://stackoverflow.com/questions/77582024/are-they-any-accessibility-concerns-with-having-a-large-button-with-a-timer-embe/77600683#77600683

stes-acc commented 2 months ago

Can we also please discuss what role according to the ARIA group those clickable icons representing secondary actions should have? These often appear in control contexts where role nesting is forbidden (e.g. close buttons in tabs).

Declaring those clickable icons presentational or aria-hidden or img does not help since they are active and deserve a role name that expresses that they are actionable. This is also helpful for tools (code parsers) to check other attributes (such as WCAG minimum size requirements for active controls).

The world needs good advice what to do here.

ChrisKerIntel commented 2 weeks ago

Hi, I heard about this from Adam Page, via Francis Storr... Adam suggested I pass along my questions about aria-actions here.

  1. Does aria-actions ever point to multiple IDs, or does there need to be a MUST in the spec saying there's only ever 1:1 relationship between aria-actions and a control?
  2. Does aria-actions need to sync with use of aria-controls or aria-owns in any specific way?
  3. Are there scenarios that aria-actions would address better ,or more simply, than existing solutions that are based partially on a use of aria-controls? I.e. "if you're using aria-controls and other code to try to do (scenario), use aria-actions and this simpler code to do that instead"?
  4. Spec says "Authors SHOULD ensure that related actions elements are visible and activatable when the current element is focused by the user agent or assistive technology." --> doesn't this have to be a MUST, otherwise it's possible to get into a condition where a control that shouldn't be available via keyboard is available to user agent, similar to "woops I made the control invisible but forgot to remove it from the tab order"?
  5. It would help to have some examples of what a use of aria-actions should look like, from perspective of the end user of e.g., a screenreader that has implemented a feature based on aria-actions. It would help me visualize use cases if I could envision, e.g., NVDA implementing use of aria-actions such that when I put focus on an element with it I hear "Inbox, button, focused, activation options include Reply, Reply All, Forward, Delete" (where the items in italics in this made up example are what NVDA knows to describe based on use of aria-actions).