Skip to content

feat(field-bitmap): make the bitmap editor keyboard and screen-reader accessible#2754

Open
mikeharv wants to merge 4 commits into
mainfrom
bitmacc
Open

feat(field-bitmap): make the bitmap editor keyboard and screen-reader accessible#2754
mikeharv wants to merge 4 commits into
mainfrom
bitmacc

Conversation

@mikeharv

@mikeharv mikeharv commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

The basics

The details

Resolves

Fixes #2752

Proposed Changes

Make @blockly/field-bitmap’s dropdown editor keyboard- and screen-reader-accessible.

Editor accessibility (similar implementation to FieldGridDropdown)

  • Builds an ARIA grid / row / gridcell structure with real <button> pixels.
  • Keyboard: arrows (hard edges, RTL-aware), Home/End/PageUp/PageDown, Enter/Space to toggle pixel.
  • Arrow keys at a hard edge play Blockly’s error beep.
  • Field-level ARIA: aria-haspopup="grid", ariaTypeName from ARIA_TYPE_FIELD_BITMAP, getAriaValue() summarizing size and filled-pixel count.

Pointer painting

  • Uses setPointerCapture so drag can continue outside the editor; pointerup / pointerleave / pointercancel end the gesture.
  • Pixel click is suppressed so it does not double-toggle after pointer paint-drag.
  • Focus: yellow Blockly focus ring; focus follows pointer on hover and while drag-painting; initial focus on first pixel when the editor opens.
  • Not technically possible with keyboard since each pixel toggle requires a key press.

Messages

  • New messages, coupled either with English hard-coded backup (for new strings).
  • Keep reading legacy BUTTON_LABEL_RANDOMIZE / BUTTON_LABEL_CLEAR if present for backwards compatibility.

DOM / CSS

  • Replace .pixelContainer / .pixelRow with .bitmapPixelGrid / .bitmapPixelRow (CSS grid + display: contents rows).
  • Add blocklyField on the on-block field group so the cursor matches other fields (default arrow, not grabby hand).
  • On-block focus indicator: create a transparent .blocklyFieldRect above the pixel grid so the yellow stroke is visible (SVG strokes are centered; pixels would otherwise cover the inner half).

Related Blockly core (separate PR in core)
New/updated Msg strings used by this plugin, including FIELD_BITMAP_PIXEL_LABEL = '%1, row %2, column %3'; (bit value spoken first) and FIELD_BITMAP_ARIA_VALUE = '%1 by %2, %3 pixels on' (dimensions are spoken "by" rather than "x").

Block label:
image

Field label with focus indicator:
image

Initial cell label with focus indicator:
image
After pressing the right arrow:
image

Reason for Changes

The bitmap editor was pointer-only and not exposed as an accessible control. Users who rely on keyboard or assistive tech could not navigate or toggle pixels reliably, and the field did not announce type/value in line with other Blockly fields.

The changes here are kept local to the plugin and no new peer dependencies are established. Before settling on this approach, I entertained the idea of refactoring @blockly/field-grid-dropdown’s Grid/GridItem so that FieldBitmap could use them too. This could have had some long-term maintenance benefits but sharing those components was resulting in a lot of API churn that didn't feel worthwhile (effectively two separate modes). Prior to this, I briefly considered making FieldBitmap extend FieldGridDropdown but this wouldn't work as it doesn't really behave like a dropdown (single-choice selection).

Test Coverage

Manually tested changes:

  • Open/close editor (Esc, click-away); focus returns via DropDownDiv ephemeral focus.
  • Keyboard: arrow navigation at edges (no wrap is intentional), Home/End, Enter/Space toggle.
  • Pointer: single-pixel toggle, drag-paint / drag-clear, paint while dragging outside the grid.
  • Hover / mid-drag focus ring tracking.
  • Screen reader / a11y tree: pixel labels (state before coordinates), field summary ("5 by 5, 10 pixels on" when Msg/fallback loaded).
  • Randomize / Clear still work; labels resolve with core messages when linked locally.
  • On-block field cursor matches other fields (blocklyField).
  • Tested changes across all renderers and in RTL. Note that Bitmap field renders outside of block bounds in zelos #2021 is still present.

Documentation

  • Note DOM/CSS class renames (.pixelContainer / .pixelRow -> .bitmapPixelGrid / .bitmapPixelRow) and <button> pixels for anyone styling the editor.

/**
* Updates the ARIA roles and label for this field.
*/
override recomputeAriaContext(): boolean {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

* @param e The keydown event.
* @param rtl Whether the workspace is RTL.
*/
private onPixelGridKeyDown(e: KeyboardEvent, rtl: boolean) {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mikeharv
mikeharv marked this pull request as ready for review July 24, 2026 18:47
@mikeharv
mikeharv requested a review from a team as a code owner July 24, 2026 18:47
@mikeharv
mikeharv requested review from gonfunko and removed request for a team July 24, 2026 18:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

FieldBitmap is not accessible

2 participants