From a293bc8fa8181885a10430f640ce01136c02444c Mon Sep 17 00:00:00 2001 From: Dejan Stajic <8886210+dejoski@users.noreply.github.com> Date: Thu, 25 Jun 2026 09:33:12 -0400 Subject: [PATCH 1/2] fix: use none ARIA role consistently Signed-off-by: Dejan Stajic <8886210+dejoski@users.noreply.github.com> --- packages/blockly/core/block_aria_composer.ts | 2 +- packages/blockly/core/block_flyout_inflater.ts | 2 +- packages/blockly/core/field_image.ts | 4 ++-- packages/blockly/core/flyout_base.ts | 2 +- packages/blockly/core/flyout_button.ts | 6 +++--- packages/blockly/core/menuitem.ts | 4 ++-- packages/blockly/core/renderers/zelos/path_object.ts | 2 +- packages/blockly/core/toolbox/category.ts | 2 +- packages/blockly/core/utils/aria.ts | 4 ++-- packages/blockly/core/utils/dom.ts | 4 ++-- packages/blockly/tests/mocha/field_image_test.js | 4 ++-- packages/blockly/tests/mocha/utils_test.js | 12 ++++++------ 12 files changed, 24 insertions(+), 24 deletions(-) diff --git a/packages/blockly/core/block_aria_composer.ts b/packages/blockly/core/block_aria_composer.ts index 3f53cdb053e..d203772c5bc 100644 --- a/packages/blockly/core/block_aria_composer.ts +++ b/packages/blockly/core/block_aria_composer.ts @@ -87,7 +87,7 @@ export function computeAriaLabel( * @param block The block to set ARIA role and roledescription attributes on. */ export function configureAriaRole(block: BlockSvg) { - setRole(block.getSvgRoot(), Role.PRESENTATION); + setRole(block.getSvgRoot(), Role.NONE); const focusableElement = block.getFocusableElement(); if (!block.isInFlyout) { // blocks in the flyout have their role set by the Flyout's block inflater diff --git a/packages/blockly/core/block_flyout_inflater.ts b/packages/blockly/core/block_flyout_inflater.ts index f8e09ddd790..355fa896a04 100644 --- a/packages/blockly/core/block_flyout_inflater.ts +++ b/packages/blockly/core/block_flyout_inflater.ts @@ -74,7 +74,7 @@ export class BlockFlyoutInflater implements IFlyoutInflater { // blocks can't be focused if they're in a flyout and not top-level // nonfocusable blocks should be hidden from the aria tree aria.setState(focusableElement, aria.State.HIDDEN, true); - aria.setRole(focusableElement, aria.Role.PRESENTATION); + aria.setRole(focusableElement, aria.Role.NONE); }); // Since getDescencdants includes the root block, we need // to correct the role and hidden state for it. diff --git a/packages/blockly/core/field_image.ts b/packages/blockly/core/field_image.ts index b65ff3bc8e9..3aa52b0d83d 100644 --- a/packages/blockly/core/field_image.ts +++ b/packages/blockly/core/field_image.ts @@ -364,11 +364,11 @@ export class FieldImage extends Field { const focusableElement = this.getFocusableElement(); // The button role is intended to indicate to users that the field has an - // editing mode that can be activated. The presentation role is used to + // editing mode that can be activated. The none role is used to // prevent screen readers from reading the content or its descendants. // Only clickable image fields are navigable. if (!this.isClickable()) { - aria.setRole(focusableElement, aria.Role.PRESENTATION); + aria.setRole(focusableElement, aria.Role.NONE); aria.clearState(focusableElement, aria.State.LABEL); return false; } diff --git a/packages/blockly/core/flyout_base.ts b/packages/blockly/core/flyout_base.ts index 36380433735..ecb9374599a 100644 --- a/packages/blockly/core/flyout_base.ts +++ b/packages/blockly/core/flyout_base.ts @@ -683,7 +683,7 @@ export abstract class Flyout if (!this.targetWorkspace.isMutator && !this.autoClose) { aria.setRole(this.getWorkspace().svgGroup_, aria.Role.REGION); } else { - aria.setRole(this.getWorkspace().svgGroup_, aria.Role.PRESENTATION); + aria.setRole(this.getWorkspace().svgGroup_, aria.Role.NONE); } // the label for a flyout includes the category name if it's available diff --git a/packages/blockly/core/flyout_button.ts b/packages/blockly/core/flyout_button.ts index 6fcb60bbaa7..de8f4d33898 100644 --- a/packages/blockly/core/flyout_button.ts +++ b/packages/blockly/core/flyout_button.ts @@ -136,7 +136,7 @@ export class FlyoutButton }, this.svgGroup!, ); - aria.setRole(shadow, aria.Role.PRESENTATION); + aria.setRole(shadow, aria.Role.NONE); } // Background rectangle. const rect = dom.createSvgElement( @@ -150,7 +150,7 @@ export class FlyoutButton }, this.svgGroup!, ); - aria.setRole(rect, aria.Role.PRESENTATION); + aria.setRole(rect, aria.Role.NONE); const svgText = dom.createSvgElement( Svg.TEXT, @@ -174,7 +174,7 @@ export class FlyoutButton .getThemeManager() .subscribe(this.svgText, 'flyoutForegroundColour', 'fill'); } - aria.setRole(svgText, aria.Role.PRESENTATION); + aria.setRole(svgText, aria.Role.NONE); // We add the word "heading" or "button" to the label so that they give appropriate hints // we can't use the corresponding roles because that overwrites the context of it being an option. diff --git a/packages/blockly/core/menuitem.ts b/packages/blockly/core/menuitem.ts index c88e9c0946b..9a789c3911c 100644 --- a/packages/blockly/core/menuitem.ts +++ b/packages/blockly/core/menuitem.ts @@ -77,9 +77,9 @@ export class MenuItem { const content = document.createElement('div'); aria.setState(element, aria.State.LABEL, this.getAriaLabel()); - // The presentation role is used to prevent screen readers from also reading the + // The none role is used to prevent screen readers from also reading the // content or its descendants. - aria.setRole(content, aria.Role.PRESENTATION); + aria.setRole(content, aria.Role.NONE); content.className = 'blocklyMenuItemContent'; let contentDom: Node = this.content as HTMLElement; diff --git a/packages/blockly/core/renderers/zelos/path_object.ts b/packages/blockly/core/renderers/zelos/path_object.ts index 36dadfa1cd1..1ceca865a6c 100644 --- a/packages/blockly/core/renderers/zelos/path_object.ts +++ b/packages/blockly/core/renderers/zelos/path_object.ts @@ -98,7 +98,7 @@ export class PathObject extends BasePathObject { 'fill': this.svgPath.getAttribute('fill') || '', 'd': this.svgPath.getAttribute('d') || '', 'transform': this.svgPath.getAttribute('transform') || '', - 'role': Role.PRESENTATION, + 'role': Role.NONE, }, this.svgRoot, ); diff --git a/packages/blockly/core/toolbox/category.ts b/packages/blockly/core/toolbox/category.ts index 014802a1560..eccbc42f547 100644 --- a/packages/blockly/core/toolbox/category.ts +++ b/packages/blockly/core/toolbox/category.ts @@ -202,7 +202,7 @@ export class ToolboxCategory this.rowDiv_.appendChild(this.rowContents_); this.iconDom_ = this.createIconDom_(); - aria.setRole(this.iconDom_, aria.Role.PRESENTATION); + aria.setRole(this.iconDom_, aria.Role.NONE); this.rowContents_.appendChild(this.iconDom_); this.labelDom_ = this.createLabelDom_(this.name_); diff --git a/packages/blockly/core/utils/aria.ts b/packages/blockly/core/utils/aria.ts index 7a9a3d8d4ac..423f3e25848 100644 --- a/packages/blockly/core/utils/aria.ts +++ b/packages/blockly/core/utils/aria.ts @@ -89,8 +89,8 @@ export enum Role { MENUITEM = 'menuitem', /** See https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Roles/option_role. */ OPTION = 'option', - /** See https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Roles/presentation_role. */ - PRESENTATION = 'presentation', + /** See https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Roles/none_role. */ + NONE = 'none', /** See https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Roles/region_role. */ REGION = 'region', /** See https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Roles/row_role. */ diff --git a/packages/blockly/core/utils/dom.ts b/packages/blockly/core/utils/dom.ts index ea279080dd6..68ce61309bb 100644 --- a/packages/blockly/core/utils/dom.ts +++ b/packages/blockly/core/utils/dom.ts @@ -58,7 +58,7 @@ export function createSvgElement( ): T { const e = document.createElementNS(SVG_NS, `${name}`) as T; /** - * For svg and group (g) elements, we set the role to presentation so that they are ignored by assistive technologies. + * For svg and group (g) elements, we set the role to none so that they are ignored by assistive technologies. */ if ( name === Svg.SVG.toString() || @@ -66,7 +66,7 @@ export function createSvgElement( e.tagName === Svg.SVG.toString() || e.tagName === Svg.G.toString() ) { - aria.setRole(e, aria.Role.PRESENTATION); + aria.setRole(e, aria.Role.NONE); } for (const key in attrs) { e.setAttribute(key, `${attrs[key]}`); diff --git a/packages/blockly/tests/mocha/field_image_test.js b/packages/blockly/tests/mocha/field_image_test.js index d8d8d7e7c9b..36607f9e0b5 100644 --- a/packages/blockly/tests/mocha/field_image_test.js +++ b/packages/blockly/tests/mocha/field_image_test.js @@ -374,9 +374,9 @@ suite('Image Fields', function () { const blockLabel = this.block.getAriaLabel(); assert.include(blockLabel, this.field.altText); }); - test('Focusable element has role of presentation', function () { + test('Focusable element has role of none', function () { const role = this.focusableElement.getAttribute('role'); - assert.equal(role, 'presentation'); + assert.equal(role, 'none'); }); test('Hidden when in a flyout', function () { this.block.isInFlyout = true; diff --git a/packages/blockly/tests/mocha/utils_test.js b/packages/blockly/tests/mocha/utils_test.js index 40461e6481d..0ca3a6fc080 100644 --- a/packages/blockly/tests/mocha/utils_test.js +++ b/packages/blockly/tests/mocha/utils_test.js @@ -435,23 +435,23 @@ suite('Utils', function () { }); suite('createSvgElement', function () { - test('svg elements of type g have the presentation role by default', function () { + test('svg elements of type g have the none role by default', function () { const svgG = Blockly.utils.dom.createSvgElement( Blockly.utils.Svg.G, {}, ); const g = Blockly.utils.dom.createSvgElement('g', {}); - assert.equal(svgG.getAttribute('role'), 'presentation'); - assert.equal(g.getAttribute('role'), 'presentation'); + assert.equal(svgG.getAttribute('role'), 'none'); + assert.equal(g.getAttribute('role'), 'none'); }); - test('svg elements of type svg have the presentation role by default', function () { + test('svg elements of type svg have the none role by default', function () { const svgSvg = Blockly.utils.dom.createSvgElement( Blockly.utils.Svg.SVG, {}, ); const svg = Blockly.utils.dom.createSvgElement('svg', {}); - assert.equal(svgSvg.getAttribute('role'), 'presentation'); - assert.equal(svg.getAttribute('role'), 'presentation'); + assert.equal(svgSvg.getAttribute('role'), 'none'); + assert.equal(svg.getAttribute('role'), 'none'); }); test('svg elements of type g reflect the role passed in when created', function () { const svgG = Blockly.utils.dom.createSvgElement(Blockly.utils.Svg.G, { From 760851382f99088628f07afe9adcf2ea66f10b8e Mon Sep 17 00:00:00 2001 From: Michael Harvey <43474485+mikeharv@users.noreply.github.com> Date: Thu, 25 Jun 2026 09:46:44 -0400 Subject: [PATCH 2/2] chore: Reorder role definitions in aria.ts --- packages/blockly/core/utils/aria.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/blockly/core/utils/aria.ts b/packages/blockly/core/utils/aria.ts index 423f3e25848..e0c4735020e 100644 --- a/packages/blockly/core/utils/aria.ts +++ b/packages/blockly/core/utils/aria.ts @@ -87,10 +87,10 @@ export enum Role { MENU = 'menu', /** See https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Roles/menuitem_role. */ MENUITEM = 'menuitem', - /** See https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Roles/option_role. */ - OPTION = 'option', /** See https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Roles/none_role. */ NONE = 'none', + /** See https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Roles/option_role. */ + OPTION = 'option', /** See https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Roles/region_role. */ REGION = 'region', /** See https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Roles/row_role. */