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

Secondary actions on items in composite widget roles #1440

Open
smhigley opened this issue Mar 26, 2021 · 37 comments · May be fixed by #1805
Open

Secondary actions on items in composite widget roles #1440

smhigley opened this issue Mar 26, 2021 · 37 comments · May be fixed by #1805
Assignees
Labels
feature may add new concept(s) to ARIA which will require implementations or APG changes priority
Milestone

Comments

@smhigley
Copy link
Contributor

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 Clarify "required owned element" #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
Copy link
Member

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
Copy link
Contributor

See: #1385

@smhigley
Copy link
Contributor Author

@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
Copy link
Contributor

mcking65 commented Jun 3, 2021

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
Copy link
Contributor

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
Copy link
Contributor

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
Copy link

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

@aleventhal
Copy link
Contributor

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
Copy link
Contributor Author

smhigley commented Jan 25, 2022

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

Pros and Cons of each approach:

Sibling pros

  • Currently would have better practical support
  • Don't need to untangle the nontrivial support blockers, including:
    • accname calculation needs to somehow exclude nested secondary actions (but not necessarily all nested interactive elements)
    • the nested interactive elements would need to be exposed somehow, likely through their parent
    • virtual cursor (for Windows screen readers) would need to be able to navigate within buttons, treeitems, options, etc.
  • We can use aria-controls to make an explicit association with ARIA

Sibling cons

  • Not as intuitive for authors
  • There is no way to author this without ARIA, and it isn't clear to me how this could be spec'd in HTML in the future
  • There is a high prevalence of nested interactive items in the wild today. If that pressures browsers and AT vendors into solving the current support issues, it makes even less sense for secondary actions to not be nested

Nested approach pros

  • The relationship exists through the nested DOM structure, without additional ARIA (maybe)
  • We might have to solve this anyway because so many people nest buttons, so it would fix two problems at once
  • We could solve existing nested interactive issues with gridcell and summary, which are largely the same -- e.g. sorting and filtering buttons on columnheader cells that are then in the column name for every cell

Nested approach cons

  • Right now HTML buttons/options/etc do not allow nested interactive elements. If used, this would only work with ARIA and we would need to convince HTML to change if we want parity
  • ATs would need to change as well. <summary> shows some of the squirrely bits, e.g. with virtual cursor not reaching nested elements
  • We need to figure out a mechanism for nested secondary actions to not contribute to the parent accname without suddenly breaking a lot of incorrectly authored code that depends on the current behavior
  • We need to figure out a mechanism for the existence of nested secondary actions to be exposed on the parent, and doing so might remove the pro of not requiring additional ARIA

Possible options for handling nested secondary actions and naming:

  • add an attribute like aria-actions that takes a space-separated list of ids
  • add an attribute (not a role, for flexibility) to denote secondary actions

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
Copy link

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

@stes-acc
Copy link

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
Copy link
Contributor

@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
Copy link
Contributor Author

@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
Copy link

@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
Copy link
Contributor

chlane commented Jan 27, 2022

@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
Copy link

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
Copy link
Contributor

cookiecrook commented Jan 27, 2022

@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
Copy link
Contributor

cookiecrook commented Jan 27, 2022

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
Copy link
Contributor

cookiecrook commented Mar 25, 2022

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
Copy link
Contributor Author

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
Copy link
Contributor Author

smhigley commented Apr 7, 2022

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

Add specific aria-actions attribute with the following requirements:

  • aria-actions is allowed on all nameable roles
  • aria-actions may reference any element with a widget role, excluding the container roles of composite widgets (e.g. it could reference a menuitem, but not a menu)

Authoring requirements for aria-actions:

  • The controls referenced by aria-actions MUST exist in the DOM
  • Authors MUST provide a keyboard mechanism to navigate to or directly activate the secondary actions.
  • 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 and follow existing conventions.

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: #1174 (comment)

@scottaohara
Copy link
Member

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 #1174 as these points are related

@scottaohara
Copy link
Member

IMO i think that would be very helpful.

@adampage
Copy link
Member

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
Copy link

jcsteh commented Oct 21, 2022

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
Copy link
Contributor

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
Copy link
Member

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
Copy link
Contributor

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
Copy link

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
Copy link

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).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature may add new concept(s) to ARIA which will require implementations or APG changes priority
Projects
None yet