From aea52b9b73ed0b445fd5ed4847b988752932d395 Mon Sep 17 00:00:00 2001
From: Jacques Newman
Date: Wed, 10 Jun 2026 15:58:09 -0700
Subject: [PATCH 01/22] Add aria-actions interactive demo
Single-page demo illustrating the proposed `aria-actions` ARIA attribute
(w3c/aria PR 1805) across three composite-widget patterns: tabs with
per-tab action buttons, listbox with per-option actions, and a data
grid with row-level actions.
Requires the `AriaActions` Blink runtime feature flag
(`chrome://flags/#enable-experimental-web-platform-features` or
`--enable-blink-features=AriaActions`).
The root README index row for the new demo is intentionally left for
a follow-up commit.
---
README.md | 1 +
aria-actions/.gitignore | 1 +
aria-actions/README.md | 25 ++
aria-actions/index.html | 623 ++++++++++++++++++++++++++++++++++++++++
aria-actions/style.css | 519 +++++++++++++++++++++++++++++++++
5 files changed, 1169 insertions(+)
create mode 100644 aria-actions/.gitignore
create mode 100644 aria-actions/README.md
create mode 100644 aria-actions/index.html
create mode 100644 aria-actions/style.css
diff --git a/README.md b/README.md
index d90c4231..9e94792d 100644
--- a/README.md
+++ b/README.md
@@ -130,6 +130,7 @@ See:
| Demo name | Description and docs | Source code & Readme | Live demo page |
|---|---|---|---|
+| ARIA Actions demo | Interactive demo for the `aria-actions` ARIA attribute, which exposes a list of secondary actions on composite-widget items (tabs, options, rows) to assistive technology. | [/aria-actions/](https://github.com/MicrosoftEdge/Demos/tree/main/aria-actions) | [ARIA Actions demo](https://microsoftedge.github.io/Demos/aria-actions/) |
| Built-in AI playgrounds | Demo pages showing how to use the built-in Prompt and Writing Assistance AI APIs in Microsoft Edge. | [/built-in-ai/](https://github.com/MicrosoftEdge/Demos/tree/main/built-in-ai) | [Built-in AI playgrounds](https://microsoftedge.github.io/Demos/built-in-ai/) demo |
| CSS Gap Decorations demos | Draws line decorations within gaps in CSS Grid, Flexbox, and Multi-column layouts. | [/css-gap-decorations/](https://github.com/MicrosoftEdge/Demos/tree/main/css-gap-decorations) | [CSS Gap Decorations demos](https://microsoftedge.github.io/Demos/css-gap-decorations/) (Readme) |
| CSS Masonry demos | Showcase the implementation of CSS Masonry layout. | [/css-masonry/](https://github.com/MicrosoftEdge/Demos/tree/main/css-masonry) | [CSS Masonry demos](https://microsoftedge.github.io/Demos/css-masonry/) (Readme) |
diff --git a/aria-actions/.gitignore b/aria-actions/.gitignore
new file mode 100644
index 00000000..32bd4e63
--- /dev/null
+++ b/aria-actions/.gitignore
@@ -0,0 +1 @@
+.screenshots/
diff --git a/aria-actions/README.md b/aria-actions/README.md
new file mode 100644
index 00000000..c592b7c9
--- /dev/null
+++ b/aria-actions/README.md
@@ -0,0 +1,25 @@
+# ARIA actions demo
+
+➡️ **[Open the demo](https://microsoftedge.github.io/Demos/aria-actions/)** ⬅️
+
+Interactive demo of [`aria-actions`](https://pr-preview.s3.amazonaws.com/w3c/aria/pull/1805.html), a proposed ARIA attribute that exposes secondary actions on an element to assistive technology. The value is an IDREFS list; each referenced element becomes an action that screen-reader users can invoke directly from the focused item.
+
+The demo covers three composite-widget patterns: tabs, a listbox, and a data grid. Naming and structure follow [ARIA PR 1805](https://github.com/w3c/aria/pull/1805) and the [APG Tabs with Action Buttons example](https://www.w3.org/WAI/ARIA/apg/patterns/tabs/examples/tabs-actions/).
+
+## Learn more
+
+- [ARIA spec PR 1805 — rendered preview](https://pr-preview.s3.amazonaws.com/w3c/aria/pull/1805.html) (current normative text)
+- [Umbrella discussion: "Secondary actions on items in composite widget roles"](https://github.com/w3c/aria/issues/1440)
+- [APG: Tabs with Action Buttons example](https://www.w3.org/WAI/ARIA/apg/patterns/tabs/examples/tabs-actions/)
+- [Proposal explainer (Sarah Higley)](https://gist.github.com/smhigley/8dbe67f834cc472e3a14bf6b289e6f0c)
+
+## Requirements
+
+The demo exercises Blink's **AriaActions** runtime feature, which is experimental and off by default in every channel. To turn it on:
+
+| Method | Instructions |
+|--------|--------------|
+| `chrome://flags` | Open `chrome://flags/#enable-experimental-web-platform-features`, set it to **Enabled**, then relaunch. |
+| Command line | Launch with `--enable-blink-features=AriaActions`. |
+
+Microsoft Edge or any Chromium-based browser will work. Firefox and Safari have not shipped support.
diff --git a/aria-actions/index.html b/aria-actions/index.html
new file mode 100644
index 00000000..3f195447
--- /dev/null
+++ b/aria-actions/index.html
@@ -0,0 +1,623 @@
+
+
+
+
+
+
+ ARIA Actions: Interactive Demo
+
+
+
+
+
+
+
ARIA Actions Demo
+
Expose secondary actions on elements to assistive technology using the
+ aria-actions attribute.
+
+
+
+
+
+
+
+
+ ⚠ aria-actions is not enabled in this browser.
+ The attribute is an experimental Blink feature behind a runtime flag.
+ Enable Experimental Web Platform features at
+ about://flags/#enable-experimental-web-platform-features
+ in Microsoft Edge (or another Chromium-based browser) and relaunch.
+ If you already enabled the flag and still see this banner, the relaunch
+ is what's missing.
+
+
+
+
+
+
+
+
+
What is aria-actions?
+
+ aria-actions is a proposed ARIA attribute. Authors point
+ it at a list of element IDs; each referenced element becomes a
+ secondary action that screen-reader users can invoke from the focused
+ item, without first moving focus to the action button.
+
+
+ The value is an IDREFS list (space-separated IDs). Each target needs
+ an accessible name, a click handler, and a keyboard path. See the
+ explainer
+ for the full authoring requirements.
+
+ Each tab points at two action buttons. A screen reader can invoke
+ Close or Pin from the tab itself; keyboard users press
+ Delete on the focused tab as a shortcut for Close.
+
+
aria-actions="close-tab-N pin-tab-N"
+
+
+ Try it: Tab into the tablist;
+ ←/→/Home/End
+ move focus, and Delete closes the focused tab. With a
+ screen reader, Close and Pin appear as actions on whichever tab has
+ focus.
+
+
+
+
+
+
+
+
+
+
+
Contents of index.html.
+
+
+
Contents of style.css.
+
+
+
Contents of app.js.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Each tab's aria-actions lists two button IDs
+
The buttons sit outside the tablist. role="tab" is
+ Children Presentational, so any interactive element nested inside a
+ tab loses its semantics; siblings are the safe place for them
+
Each button also sets aria-controls back to its tab.
+ That fits here because Close and Pin really do control the tab
+ (the listbox and grid sections omit the back-reference for that
+ reason)
+
Delete on the focused tab triggers Close;
+ aria-keyshortcuts tells AT about the shortcut
+
+
+
+
+
+
+
+
Listbox with Actions
+
+ Each option points at two per-item buttons. AT users invoke Edit or
+ Delete from the option without moving off it. The same buttons live
+ in a side panel next to the listbox, so non-AT keyboard users can Tab
+ over and press them too.
+
+
aria-actions="edit-item-N delete-item-N"
+
+
+ Try it: Tab into the listbox;
+ ↑/↓/Home/End
+ change the selection. Tab again to land on the side panel and press
+ Edit or Delete by keyboard. Esc from a button returns
+ focus to the listbox. With a screen reader, both actions are listed
+ on whichever option has focus.
+
+
+
+
+
+
MDN Web Docs
+
CSS Tricks
+
Web.dev
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Each role="option" lists its action button IDs in
+ aria-actions
+
The buttons cannot live inside the <li>:
+ role="option" is Children Presentational in ARIA
+ 1.2/1.3, so any nested interactive element loses its semantics.
+ They live in a side panel instead
+
The JS keeps tabindex and aria-selected
+ in sync as ↑/↓/Home/End
+ move the selection
+
Tab reaches the side panel; Esc sends focus back to
+ the listbox
+
The side panel uses role="group" so its
+ aria-label reaches AT. A bare <div>
+ would swallow the label
+
+
+
+
+
+
+
+
Grid with Row Actions
+
+ Each row exposes its action buttons via aria-actions set
+ on the <tr>. AT users invoke View details or
+ Archive from the row, without descending into the Actions cell.
+
+
aria-actions="view-row-N archive-row-N"
+
+
+ Try it: Tab into the grid;
+ ↑/↓/Home/End
+ move between rows. Tab from a row to reach its action buttons, and
+ Esc to return. With a screen reader, View and Archive
+ appear as actions on whichever row has focus.
+
+
+
+
+
+
+
Order
+
Customer
+
Status
+
Actions
+
+
+
+
+
#1024
+
Alice Johnson
+
Shipped
+
+
+
+
+
+
+
+
+
#1025
+
Bob Chen
+
Processing
+
+
+
+
+
+
+
+
+
#1026
+
Carol Davis
+
Delivered
+
+
+
+
+
+
+
+
+
+
+
+
+
aria-actions on each role="row" exposes
+ the row's actions
+
The buttons live in the Actions column. Only the focused row's
+ buttons are Tab stops; the JS swaps tabindex as row
+ focus moves
+
Esc from a button returns focus to its row
+ (APG grid widget-mode)
+
The exact set of roles that can carry aria-actions
+ is still under discussion in PR 1805.
+ So far the consensus targets child roles of composite widgets:
+ tabs, options, rows, gridcells, treeitems, and similar
+
Roving tabindex on <tr> plus the
+ arrow-key handler make the grid keyboard-operable
elements
+ (option has Children Presentational: True; nested interactives would
+ lose their semantics). */
+.listbox-with-actions {
+ display: grid;
+ grid-template-columns: 1fr auto;
+ border: 1px solid var(--border);
+ border-radius: var(--radius);
+ max-width: 500px;
+ background: var(--bg-card);
+ overflow: hidden;
+}
+
+.listbox-with-actions .listbox {
+ border: none;
+ border-radius: 0;
+ max-width: none;
+ margin: 0;
+}
+
+.listbox {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+ border: 1px solid var(--border);
+ border-radius: var(--radius);
+ max-width: 400px;
+}
+
+.listbox-option {
+ padding: 0.6rem 1rem;
+ border-bottom: 1px solid var(--border);
+ cursor: default;
+}
+
+.listbox-option:last-child {
+ border-bottom: none;
+}
+
+.listbox-option:hover {
+ background: var(--hover-bg);
+}
+
+.listbox-option[aria-selected="true"] {
+ background: var(--accent-light);
+}
+
+.bookmark-actions {
+ display: grid;
+ grid-template-rows: repeat(3, 1fr);
+ border-left: 1px solid var(--border);
+}
+
+.bookmark-actions .action-row {
+ display: flex;
+ gap: 0.25rem;
+ align-items: center;
+ padding: 0.6rem 1rem;
+ border-bottom: 1px solid var(--border);
+}
+
+.bookmark-actions .action-row:last-child {
+ border-bottom: none;
+}
+
+.bookmark-actions button {
+ padding: 0.2rem 0.5rem;
+ font-size: 0.8rem;
+ border: 1px solid var(--border);
+ border-radius: 3px;
+ background: var(--bg-card);
+ color: var(--text);
+ cursor: pointer;
+}
+
+.bookmark-actions button:hover {
+ background: var(--hover-bg);
+}
+
+/* ----- Grid ----- */
+.data-grid {
+ width: 100%;
+ border-collapse: collapse;
+ font-size: 0.9rem;
+}
+
+.data-grid th,
+.data-grid td {
+ border: 1px solid var(--border);
+ padding: 0.6rem 0.75rem;
+ text-align: left;
+}
+
+.data-grid th {
+ background: var(--code-bg);
+ font-weight: 600;
+}
+
+.data-grid tbody tr:hover td {
+ background: var(--hover-bg);
+}
+
+/* Row focus is the primary unit for grid keyboard nav; show a visible
+ indicator on the focused row. */
+.data-grid tbody tr:focus-visible {
+ outline: 2px solid var(--focus-color);
+ outline-offset: -2px;
+}
+
+.row-actions {
+ display: flex;
+ gap: 0.25rem;
+}
+
+.row-actions button {
+ padding: 0.2rem 0.5rem;
+ font-size: 0.8rem;
+ border: 1px solid var(--border);
+ border-radius: 3px;
+ background: var(--bg-card);
+ color: var(--text);
+ cursor: pointer;
+}
+
+.row-actions button:hover {
+ background: var(--hover-bg);
+}
+
+/* ----- Inline Code ----- */
+code {
+ font-family: Consolas, Monaco, "Courier New", monospace;
+ font-size: 0.9em;
+ background: var(--code-bg);
+ padding: 0.1rem 0.3rem;
+ border-radius: 3px;
+}
+
+/* ----- Links ----- */
+a {
+ color: var(--accent);
+}
+
+/* ----- Forced Colors Mode (Windows High Contrast) -----
+ Ensure selected states and focus rings are conveyed via system
+ colors (which override CSS colors in HCM). */
+@media (forced-colors: active) {
+ :focus-visible {
+ outline: 2px solid Highlight;
+ outline-offset: 2px;
+ }
+
+ .tablist .tab[aria-selected="true"] {
+ border-bottom-color: Highlight;
+ color: Highlight;
+ }
+
+ .listbox-option[aria-selected="true"] {
+ background: Highlight;
+ color: HighlightText;
+ forced-color-adjust: none;
+ }
+
+ .data-grid tbody tr:focus-visible {
+ outline: 2px solid Highlight;
+ }
+}
From 9b189a2885f9c8b1a33fdfd4787310e9ad4aa245 Mon Sep 17 00:00:00 2001
From: Jacques Newman
Date: Wed, 17 Jun 2026 13:16:32 -0700
Subject: [PATCH 02/22] [aria-actions] Remove window.alert, reframe spec prose
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- Replace window.alert() in the delegated data-action click handler with
a polite live region (#action-toast, role=status aria-live=polite
aria-atomic=true). Toast is always in the DOM, visible only when
non-empty, auto-clears after 4s, and honours prefers-reduced-motion
and forced-colors. No focus is moved.
- Reframe forward-looking prose now that the attribute is shipping behind
a flag: "a proposed ARIA attribute" -> "a new ARIA attribute"
(index.html:57, README.md:5); "Spec status … still under review" ->
"Reference … defines the attribute" (index.html:69-77); "still under
discussion in PR 1805 … the consensus targets …" -> "defined by
PR 1805 and targets …" (index.html:352-355). Runtime-flag and
Firefox/Safari-haven't-shipped wording in the README is left untouched
because it's still accurate.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---
aria-actions/README.md | 2 +-
aria-actions/index.html | 41 ++++++++++++++++++++++++++++++----------
aria-actions/style.css | 42 +++++++++++++++++++++++++++++++++++++++++
3 files changed, 74 insertions(+), 11 deletions(-)
diff --git a/aria-actions/README.md b/aria-actions/README.md
index c592b7c9..d4080251 100644
--- a/aria-actions/README.md
+++ b/aria-actions/README.md
@@ -2,7 +2,7 @@
➡️ **[Open the demo](https://microsoftedge.github.io/Demos/aria-actions/)** ⬅️
-Interactive demo of [`aria-actions`](https://pr-preview.s3.amazonaws.com/w3c/aria/pull/1805.html), a proposed ARIA attribute that exposes secondary actions on an element to assistive technology. The value is an IDREFS list; each referenced element becomes an action that screen-reader users can invoke directly from the focused item.
+Interactive demo of [`aria-actions`](https://pr-preview.s3.amazonaws.com/w3c/aria/pull/1805.html), a new ARIA attribute that exposes secondary actions on an element to assistive technology. The value is an IDREFS list; each referenced element becomes an action that screen-reader users can invoke directly from the focused item.
The demo covers three composite-widget patterns: tabs, a listbox, and a data grid. Naming and structure follow [ARIA PR 1805](https://github.com/w3c/aria/pull/1805) and the [APG Tabs with Action Buttons example](https://www.w3.org/WAI/ARIA/apg/patterns/tabs/examples/tabs-actions/).
diff --git a/aria-actions/index.html b/aria-actions/index.html
index 3f195447..d0d43f0e 100644
--- a/aria-actions/index.html
+++ b/aria-actions/index.html
@@ -54,7 +54,7 @@
ARIA Actions Demo
What is aria-actions?
- aria-actions is a proposed ARIA attribute. Authors point
+ aria-actions is a new ARIA attribute. Authors point
it at a list of element IDs; each referenced element becomes a
secondary action that screen-reader users can invoke from the focused
item, without first moving focus to the action button.
@@ -66,9 +66,9 @@
The set of roles that can carry aria-actions
+ is defined by PR 1805
+ and targets child roles of composite widgets: tabs, options, rows,
+ gridcells, treeitems, and similar
Roving tabindex on <tr> plus the
arrow-key handler make the grid keyboard-operable