Parsons accessibility - #1453
Conversation
There was a problem hiding this comment.
🟡 Changes recommended
Disabled blocks can skip click-handler initialization, leading to a potential runtime error when removing the click listener during disable/destroy flows.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR improves accessibility and keyboard navigation for the Runestone Parsons interactive by shifting keyboard entry to the sortable container, enhancing screen-reader announcements (including MathJax speech extraction), replacing alert-based help messaging with live-region updates, and adding visual focus/move cues.
Changes:
- Refactors keyboard interaction to require explicit activation (Enter/Space) and centralizes key handling in the Parsons container.
- Adds accessible labels/announcements for blocks (including MathJax speech text) and improves live-region messaging for adaptive help.
- Updates styling for keyboard-selection states and adds localized text for the new keyboard activation hint.
File summaries
| File | Description |
|---|---|
| bases/rsptx/interactives/runestone/parsons/test/parsons.test.js | Updates/adds tests for the new keyboard activation model, aria-label behavior, and live-region help messaging. |
| bases/rsptx/interactives/runestone/parsons/js/parsonsBlock.js | Adds ARIA role on blocks and refactors focus/click behavior for keyboard interaction. |
| bases/rsptx/interactives/runestone/parsons/js/parsons.js | Implements the new keyboard activation flow, live announcements, MathJax speech observation, and message handling refactor. |
| bases/rsptx/interactives/runestone/parsons/js/parsons-i18n.en.js | Adds localized “Enter to activate” message key. |
| bases/rsptx/interactives/runestone/parsons/js/parsons-i18n.pt-br.js | Adds localized “Enter to activate” message key. |
| bases/rsptx/interactives/runestone/parsons/js/parsons-i18n.sr-Cyrl.js | Adds localized “Enter to activate” message key. |
| bases/rsptx/interactives/runestone/parsons/css/parsons.css | Adds keyboard overlay container styling and new outlines for selected/moving block states. |
Review details
- Files reviewed: 7/7 changed files
- Comments generated: 2
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
|
Updated to address issues. Note that translations for other languages are AI generated. They look OK based on a quick check with google translate, but might need fine tuning. |
There was a problem hiding this comment.
🟡 Changes recommended
Several newly introduced keyboard/a11y paths can break or behave incorrectly in real usage (selector support exception risk, stale live-region updates, and focused-block disable/destroy cleanup).
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
Suppressed comments (4)
Previously missed (2) — in code that hasn't changed since the last review.
bases/rsptx/interactives/runestone/parsons/js/parsons.js:197
getBlockLabelderives the accessible label from the entire block container, which can include non-code decorations (e.g., left/right numbering labels) and make screen readers announce extra text. Use the.lineselement as the source for accessible text so only the block content (and MathJax speech) is used.
getBlockLabel(block) {
return getAccessibleElementText(block.view) || t("msg_parson_block");
}
bases/rsptx/interactives/runestone/parsons/js/parsons.js:3221
showMessageupdatesmessageDivasynchronously viasetTimeout, butclearFeedbackdoesn't invalidate pending updates. IfclearFeedback()runs within the 10ms window, the delayed callback can repopulate the live region after it's been cleared/hidden, leading to stale announcements. BumpmessageVersionand clear the message contents when clearing feedback.
this.messageDiv.style.visibility = "hidden";
this.pendingHelpMessage = undefined;
this.hideBlockExplanations();
this.updateBlockAriaLabels();
bases/rsptx/interactives/runestone/parsons/js/parsonsBlock.js:444
disable()still checks fortabindex == "0", but blocks are no longer assignedtabindex="0"(the sortable container is now the entry point). This makes the focused-block cleanup path unreachable and can leavetextFocus/keyboard state pointing at a disabled block. Usethis.problem.textFocus === thisto decide whether to cancel keyboard mode when disabling.
This issue also appears on line 466 of the same file.
this.view.removeEventListener("click", this.clickHandler);
if (this.view.getAttribute("tabindex") == "0") {
this.releaseFocus();
this.view.removeAttribute("tabindex");
this.problem.initializeTabIndex();
bases/rsptx/interactives/runestone/parsons/js/parsonsBlock.js:470
destroy()also checks fortabindex == "0", which is now unreachable. If the destroyed block is the currenttextFocus, the component can retain stale keyboard state referencing a removed element. Cancel keyboard mode when destroying the focused block.
this.view.removeEventListener("click", this.clickHandler);
if (this.view.getAttribute("tabindex") == "0") {
this.releaseFocus();
}
this.view.removeAttribute("tabindex");
- Files reviewed: 7/7 changed files
- Comments generated: 1
- Review effort level: Lite
Fixes some accessibility issues with Parsons.
Note: Keyboard navigation now requires activation - use tab to focus on the block area and then hit enter.
This pull request introduces several accessibility and keyboard navigation improvements to the Parsons problem interactive, along with related visual and internationalization updates. The most significant changes enhance the keyboard navigation experience for users, provide clearer visual cues during keyboard interactions, and add new localized messages. The changes also refactor event handling and focus management to better support these features.
Accessibility and Keyboard Navigation Improvements:
Added
role="button"to each Parsons block and improved keyboard event handling, allowing users to activate and move blocks using the keyboard. Focus management and event listeners were refactored to support keyboard navigation and movement modes. (parsonsBlock.js) [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] [14] [15] [16] [17] [18] [19] [20] [21]Added a new absolutely positioned, pointer-events-disabled container (
.parsons-keyboard-application) to the Parsons widget for improved keyboard navigation overlays. (parsons.css)Visual Feedback Enhancements:
.block.downand.block.upstates, providing clear visual cues when a block is selected or being moved via keyboard. (parsons.css)Internationalization:
parsons-i18n.en.js,parsons-i18n.pt-br.js,parsons-i18n.sr-Cyrl.js) [1] [2] [3]These changes collectively make the Parsons problem interactive more accessible and user-friendly, especially for keyboard users.