Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Secondary Actions Proposal

Secondary Actions Proposal

This is a both an explainer for why a secondary actions proposal is needed, and a draft of the proposed change to the ARIA spec.

Original issue: w3c/aria#1440

Jump straight to the Proposal

What are secondary actions?

Secondary actions are, as the name implies, additional interactive items that are related to one primary interactive control within a composite widget. This proposal specifically concerns interactive children of these roles:

  • combobox
  • grid
  • listbox
  • menu
  • menubar
  • tablist
  • tree
  • treegrid

This pattern is increasingly common in the wild. Here are some real-world examples of secondary actions on a tab button, a menu item, and a tree item:

the VS Code tab list of open files, the selected tab has a visible close button 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 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

While compound widget roles have the most immediate need for secondary action semantics, the pattern could also apply to a range of other control types. Some examples include:

  • The menu button in a splitbutton
  • a dialog with a close action

Challenges in authoring secondary action patterns today

There are two potential DOM structures for secondary actions in composite widgets. Using tablist roles as an example (and excluding non-relevant attributes):

1. Child actions

<div role="tablist">
  <div role="tab">
    Item 1
    <button>secondary action</button>
  </div>
</div>

Problems:

  • The tab role has Children presentational: true, meaning it strips the semantics from any child elements. Per the spec, the child button should not be exposed as a button, causing it to be undiscoverable by screen reader virtual cursor, and causing inconsistencies when focus lands on it.
  • The calculated name for the tab button would be "Item 1 secondary action" instead of "Item 1"

2. Sibling actions

<div role="tablist">
  <div role="tab">Item 1</div>
  <button>secondary action</button>
</div>

Problems:

  • While the spec is ambiguous about whether buttons can be descendants of a tablist (ref: w3c/aria#1454), it isn't explicitly allowed and creates inconsistencies in practice (e.g. numbering of items in the tablist, screen reader mode switching when focus is on the button).
  • The "Item 1" tab button and the secondary action are not clearly associated.
  • Likely less intuitive for authors
  • usually requires an extra wrapping node for styling/layout

General problems with both approaches

  • There is no consistent way to expose the existence of related secondary actions without including them in the accessible name, which is verbose and repetitive.
  • While nested secondary actions have more practical issues in screen readers today, miscellaneous sibling interactive items also don't have perfect support. (testing results: https://a11y-screenreader-demos.netlify.app/studies/secondary-actions/)

Goals

These are the functional needs that a spec solution to secondary actions would ideally fulfill:

  1. Support both child and sibling secondary action markup patterns.
  2. Surface the existence of secondary actions to screen reader users when focus/virtual cursor is on the primary interactive element.
  3. Exclude secondary actions from the primary action's accessible name when they are nested.
  4. Solve #2 and #3 for patterns that currently allow nested interactive items, e.g. tree and grid.
  5. Enable an accessible semantic mapping for new patterns like Open UI's selectmenu that may contain nested interactive elements.
  6. Potentially enable custom screen reader actions UI, as mentioned in this comment: w3c/aria#762 (comment)

Proposal

  1. Create an aria-actions attribute that accepts a space-separated list of ids pointing at related interactive controls.
  2. (Potential action): remove "Children Presentational" from menuitemcheckbox, menuitemradio, tab, and option in the ARIA spec
  3. (Potential addition): referenced secondary actions should have aria-controls pointing back at the id of the primary action.

Removing "children presentational" from composite widget child roles that don't allow it has both pros and cons. Including the child actions in the accessibility tree would improve virtual cursor access for screen readers with a virtual cursor, but would potentially add a large number of very repetitive buttons/links/etc to the accessibility tree in the case of long sets of items that each have the same action or actions.

Preserving the current "children presentational" semantics could work, provided child secondary actions have their semantics exposed when focused. The downside is that screen readers would either need to develop their own UI to activate secondary actions from the primary action (similar to VoiceOver's actions menu), or users would need to rely on the authored keyboard interaction to access them.

Scope of roles that allow aria-actions:

There are multiple options for defining allowed roles for aria-actions, ranging from least permissive to most permissive:

  • children of composite widget roles
  • all widget roles
  • all nameable roles (i.e. excluding roles with name prohibited)
  • all roles excluding generic

The benefit of a more permissive set of allowed roles is that it enables authors to accessibly mark up complex UI beyond what we've actively thought of in this proposal, or beyond what exists today.

The primary drawbacks are that it introduces more potential for unforseen complications, and more potential for misuse to become widespread enough that screen readers drop support.

One note in support of the "all nameable roles": this captures the set of roles that are individually reachable by AT without limiting authors. As an example, if an author wished to

Scope of roles that allow reference by aria-actions:

There are also a couple options for limiting (or not limiting) the scope of what can be referenced with aria-actions. As a general approach to limiting allowed referenced elements, targeting nameable, focusable roles seems most logical. Some variations of that include:

  • All widget roles
  • All widget roles apart from composite widget roles (this would still allow their children, e.g. menuitem, to be referenced)
  • Any element that supports an accessible name and is focusable or has a click action

Authoring requirements for aria-actions:

  • The referenced controls 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 calculation 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.

Next steps

If this mechanism gets support, we would need to:

  1. Determine Accessibility API mappings for aria-actions (this would likely be the general ARIA bucket API prop)
  2. Contact screen reader vendors to determine appetite to support aria-actions by surfacing some sort of "actions available" announcement, and improving support for nested interactive items.
  3. Work with browser vendors and Open UI to implement the aria-actions API mappings by default for nested interactive items in new proposed composite widget elements like selectmenu.
@cookiecrook
Copy link

cookiecrook commented Mar 25, 2022

Some prior discussion:

@cookiecrook
Copy link

cookiecrook commented Mar 25, 2022

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

I'm mostly wordsmithing b/c conventional or discoverable seems a bit hard to translate to specifics to me. Maybe there could be an additional SHOULD around discoverability?

👍 to both

Another good example might be tabs with close buttons using ctrl + w to close instead of adding the close button to the tab order.

Yep, with the caveat that web authors rarely get modifier commands right, as they are difficult to consistently implement in an internationalized and cross-platform way due to different keyboard layouts and platform conventions.

@stes-acc
Copy link

stes-acc commented Mar 31, 2022

Another good example might be tabs with close buttons using ctrl + w to close instead of adding the close button to the tab order.

Yep, with the caveat that web authors rarely get modifier commands right, as they are difficult to consistently implement in an internationalized and cross-platform way due to different keyboard layouts and platform conventions.

We use the DELETE key here with good success.

Another topic is to enable keyboard access in an intuitive way also covering different interaction channels. We

  • should include secondary actions always also in the SHIFT+F10 (Windows) context menu of a tab
  • add respective info of hotkeys in tooltips of secondary action icons
  • pimp aria-action pointers in a way that the browser detects and maps it to browser-defined shortcuts
  • apply aria-keyshortcuts (when focusing the tab) by having secondary action activation shortcuts in sequential manner in keyshortcuts list

@cookiecrook
Copy link

cookiecrook commented Apr 2, 2022

We use the DELETE key here with good success.

I would not expect the Delete key as a common way to close a window. Escape is a more common native platform and web convention for closing dialogs and sub-level views. Some implementations are already synthesizing Escape in relevant contexts. Also synthesized arrow keys for increment/decrement on range widgets like ARIA sliders. See the User Action Events tables in the AOM Explainer.

Effectively this would be similar, in that the AT action would cause a single click event to occur on the referenced clickable element that triggers the related action.

@stes-acc
Copy link

stes-acc commented Apr 14, 2022

We use the DELETE key here with good success.

I would not expect the Delete key as a common way to close a window. Escape is a more common native platform and web convention for closing dialogs and sub-level views. Some implementations are already synthesizing Escape in relevant contexts. Also synthesized arrow keys for increment/decrement on range widgets like ARIA sliders. See the User Action Events tables in the AOM Explainer.

Effectively this would be similar, in that the AT action would cause a single click event to occur on the referenced clickable element that triggers the related action.

This is a total misunderstanding. OF COURSE we use ESC to close dialogs - what else? My statement was referring to the need to define a key for the "x" in tokens, tabs etc. to remove things, and here the DEL key is the one we use.

@mcking65
Copy link

mcking65 commented Apr 14, 2022

Given there is some possibility we will need screen reader support for this to work, I'd like to suggest we use both APG and aria-at to prove not just implementability but efficacy. I'd like to avoid some of the problems we have had in the past where we assumed the rest of the world would just come along for the ride and make everything work in practice. Something that makes changes this fundamental will not yield interoperable and user-pleasing results if we don't adress the entire dependency chain from the start.

In practice, this means both building examples and writing aria-at test cases for those examples as part of the spec formation process.

@smhigley
Copy link
Author

smhigley commented Apr 14, 2022

Link to a comment with specific suggested spec wording: w3c/aria#1440 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment