From 43e7d9f430928b8d290d055ad775051124f735a0 Mon Sep 17 00:00:00 2001 From: Brian Genisio Date: Tue, 18 Aug 2026 13:53:16 -0400 Subject: [PATCH 1/2] docs(a11y): Record A9 as closed on main Co-authored-by: Cursor --- a11y-audits/8-13-26/resolution-plan.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/a11y-audits/8-13-26/resolution-plan.md b/a11y-audits/8-13-26/resolution-plan.md index 2204295..be2138d 100644 --- a/a11y-audits/8-13-26/resolution-plan.md +++ b/a11y-audits/8-13-26/resolution-plan.md @@ -249,7 +249,7 @@ Fill issue/PR numbers when filing. Never write “this PR”. | A5 | #24 | 1 (bundle Sort) | #36 | Closed (PR #36) | | A6 | #25 | 1 (bundle Sort) | #36 | Closed (PR #36) | | A3 | #26 | 1 | #37 | Closed (PR #37) | -| A9 | #27 | 1 | | Open | +| A9 | #27 | 1 | #38 | Closed (PR #38) | | A11 | #28 | 1 | | Open | | D2 | [DS #28](https://github.com/CodeSignal/learn_bespoke-design-system/issues/28) | 1 ∥ | | Open | | D1 | [DS #29](https://github.com/CodeSignal/learn_bespoke-design-system/issues/29) | 1 ∥ / 3 | | Open | @@ -273,4 +273,4 @@ Fill issue/PR numbers when filing. Never write “this PR”. ## Next step -P1–P7 confirmed as the recommended defaults. Wave 0 is on `main` (PR #20). A1 is on `main` (PR #35). Sort bundle is on `main` (PR #36). A3 is on `main` (PR #37). Wave 1 continues with A9 (`fix/a11y-iframe-title`, #27). +P1–P7 confirmed as the recommended defaults. Wave 0 is on `main` (PR #20). A1 is on `main` (PR #35). Sort bundle is on `main` (PR #36). A3 is on `main` (PR #37). A9 is on `main` (PR #38). Wave 1 continues with A11 (`fix/a11y-matching-listbox`, #28). From f6c4e4bb038ae5a5f38cc1e5a1a6d12f2289f7fd Mon Sep 17 00:00:00 2001 From: Brian Genisio Date: Tue, 18 Aug 2026 13:53:16 -0400 Subject: [PATCH 2/2] fix(a11y): Treat Matching choices as a labeled group of buttons Co-authored-by: Cursor --- public/modules/matching.js | 3 +-- test/a11y-characterization.test.js | 10 ++++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/public/modules/matching.js b/public/modules/matching.js index 625d619..bf247a3 100644 --- a/public/modules/matching.js +++ b/public/modules/matching.js @@ -22,7 +22,7 @@ export function initMatching({ elContainer.innerHTML = `
-
+
`; @@ -212,7 +212,6 @@ export function initMatching({ const choiceButton = document.createElement('button'); choiceButton.className = 'matching-choice-button button button-primary body-large'; choiceButton.textContent = choice; - choiceButton.setAttribute('role', 'option'); choiceButton.setAttribute('aria-label', `Select ${choice}`); // Check if this choice is available diff --git a/test/a11y-characterization.test.js b/test/a11y-characterization.test.js index 72a5cf2..3685a0c 100644 --- a/test/a11y-characterization.test.js +++ b/test/a11y-characterization.test.js @@ -116,10 +116,12 @@ test('A9: side-content iframe has a title from content type', () => { ); }); -test('A11 characterization: Matching choices are buttons with role=option in a listbox', () => { - // Wave 1 A11 drops listbox/option on native buttons. +test('A11: Matching choices are a labeled group of buttons', () => { const src = read('public/modules/matching.js'); - assert.match(src, /role="listbox"/); + assert.doesNotMatch(src, /role="listbox"/); + assert.doesNotMatch(src, /setAttribute\(\s*'role',\s*'option'\s*\)/); + assert.match(src, /id="matching-choices"[^>]*role="group"/); + assert.match(src, /aria-label="Answer choices"/); assert.match(src, /createElement\('button'\)/); - assert.match(src, /setAttribute\(\s*'role',\s*'option'\s*\)/); + assert.match(src, /choiceButton\.disabled\s*=\s*true/); });