Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions packages/blockly/core/workspace_svg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ import * as registry from './registry.js';
import * as blockRendering from './renderers/common/block_rendering.js';
import type {Renderer} from './renderers/common/renderer.js';
import type {ScrollbarPair} from './scrollbar_pair.js';
import {names as ShortcutNames} from './shortcut_items.js';
import type {Theme} from './theme.js';
import {Classic} from './theme/classic.js';
import {ThemeManager} from './theme_manager.js';
Expand All @@ -82,6 +83,7 @@ import * as dom from './utils/dom.js';
import * as drag from './utils/drag.js';
import type {Metrics} from './utils/metrics.js';
import {Rect} from './utils/rect.js';
import {getShortcutKeysShort} from './utils/shortcut_formatting.js';
import {Size} from './utils/size.js';
import {Svg} from './utils/svg.js';
import * as svgMath from './utils/svg_math.js';
Expand Down Expand Up @@ -349,6 +351,12 @@ export class WorkspaceSvg
*/
private navigator = new Navigator();

/**
* Whether this workspace has ever been focused. Used to announce usage hints
* to screenreaders on initial focus only.
*/
private everFocused = false;

/**
* @param options Dictionary of options.
*/
Expand Down Expand Up @@ -2742,6 +2750,15 @@ export class WorkspaceSvg
if (!this.isFlyout && !this.isMutator) {
this.updateAriaLabel();
}
if (!this.everFocused && !this.options.parentWorkspace) {
aria.announceDynamicAriaState(
Msg['SCREENREADER_HINT'].replace(
'%1',
getShortcutKeysShort(ShortcutNames.TOGGLE_SCREENREADER),
),
);
this.everFocused = true;
}
}

/** See IFocusableNode.onNodeBlur. */
Expand Down
4 changes: 3 additions & 1 deletion packages/blockly/msg/json/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"@metadata": {
"author": "Ellen Spertus <ellen.spertus@gmail.com>",
"lastupdated": "2026-05-14 08:47:43.920300",
"lastupdated": "2026-05-13 14:56:12.075780",
"locale": "en",
"messagedocumentation" : "qqq"
},
Expand Down Expand Up @@ -529,5 +530,6 @@
"SCREENREADER_MODE_DISABLED": "Screenreader mode is off, press %1 to turn it on",
"CURRENT_BLOCK_ANNOUNCEMENT": "Current block: %1",
"PARENT_BLOCKS_ANNOUNCEMENT": "Parent blocks: %1",
"NO_PARENT_ANNOUNCEMENT": "Current block has no parent"
"NO_PARENT_ANNOUNCEMENT": "Current block has no parent",
"SCREENREADER_HINT": "Use the arrow keys to navigate. Press %1 to toggle screenreader accessibility mode."
}
3 changes: 2 additions & 1 deletion packages/blockly/msg/json/qqq.json
Original file line number Diff line number Diff line change
Expand Up @@ -523,5 +523,6 @@
"SCREENREADER_MODE_DISABLED": "Message announced when screenreader optimization mode is turned off.",
"CURRENT_BLOCK_ANNOUNCEMENT": "Screenreader announcement providing context about the currently focused block.",
"PARENT_BLOCKS_ANNOUNCEMENT": "Screenreader announcement providing context about the currently focused block's parents.",
"NO_PARENT_ANNOUNCEMENT": "Screenreader announcement informing users that the currently focused block has no parent blocks."
"NO_PARENT_ANNOUNCEMENT": "Screenreader announcement informing users that the currently focused block has no parent blocks.",
"SCREENREADER_HINT": "Message announced when screenreader optimization mode is turned off."
}
3 changes: 3 additions & 0 deletions packages/blockly/msg/messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -2090,3 +2090,6 @@ Blockly.Msg.PARENT_BLOCKS_ANNOUNCEMENT = 'Parent blocks: %1';
/** @type {string} */
/// Screenreader announcement informing users that the currently focused block has no parent blocks.
Blockly.Msg.NO_PARENT_ANNOUNCEMENT = 'Current block has no parent';
/** @type {string} */
/// Message announced when screenreader optimization mode is turned off.
Blockly.Msg.SCREENREADER_HINT = 'Use the arrow keys to navigate. Press %1 to toggle screenreader accessibility mode.';
22 changes: 22 additions & 0 deletions packages/blockly/tests/mocha/workspace_svg_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,28 @@ suite('WorkspaceSvg', function () {
assert.isNotNull(gesture);
});

test('Announces a screenreader hint on first focus', function () {
document.getElementById('blocklyAriaAnnounce').textContent = '';
Blockly.getFocusManager().focusNode(this.workspace);
this.clock.runAll();
assert.include(
document.getElementById('blocklyAriaAnnounce').textContent,
'Use the arrow keys to navigate',
);
});

test('Nested workspaces do not announce screenreader hints', function () {
document.getElementById('blocklyAriaAnnounce').textContent = '';
Blockly.getFocusManager().focusNode(
this.workspace.getFlyout().getWorkspace(),
);
this.clock.runAll();
assert.notInclude(
document.getElementById('blocklyAriaAnnounce').textContent,
'Use the arrow keys to navigate',
);
});

suite('updateToolbox', function () {
test('Passes in null when toolbox exists', function () {
assert.throws(
Expand Down
Loading