Skip to content

Conversation

@BenHenning
Copy link
Collaborator

@BenHenning BenHenning commented Dec 11, 2025

The basics

The details

Resolves

Fixes #9495

Proposed Changes

Changes a bunch of ARIA role & label management to ensure that Flyout acts like a list rather than a tree.

Reason for Changes

Flyouts are always hierarchically flat so it doesn't make sense to model them as a tree. Instead, a menu is likely a better fit per https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Roles/menu_role:

A menu generally represents a grouping of common actions or functions that the user can invoke. The menu role is appropriate when a list of menu items is presented in a manner similar to a menu on a desktop application. Submenus, also known as pop-up menus, also have the role menu.

However, there are important caveats that need to be considered and addressed:

  • As discussed below, menus introduce some unexpected compatibility issues with VoiceOver so this PR presently uses list and listitems as a slightly more generic enumerating alternative for menus.
  • Menus (and to some extent lists) are stricter* than trees in that they seem to impose a requirement that menuitems cannot contain interactive elements (they are expected to be interactive themselves). This has led to a few specific changes:
    • Block children are now hidden when in the flyout (since they aren't navigable anyway).
    • Flyout buttons are themselves now the menuitem rather than their container parent, and they no longer use the role button.
  • Menus aren't really expected to contain labels but it isn't inherently disallowed. This is less of an issue with lists.
  • Because everything must be a listitem (or a few more specific alternatives) both blocks and buttons lack some context. Since not all Flyout items can be expected to be interactive, buttons and blocks have both had their labels updated to include an explicit indicator that they are buttons and blocks, respectively. Note that this does possibly go against convention for buttons in particular but it seems fine since this is an unusual (but seemingly correct) utilization of a list element.
  • To further provide context on blocks, the generated label for blocks in the Flyout is now its verbose label rather than the more compact form.

* This is largely a consequence of a few specific attributes of menuitem and menus as a whole and very likely also applies to trees and treeitems (and lists and listitemss). However, now seemed like a good time to fix this especially in case some screen readers get confused rather than ignore nested interactive controls/follow semantic cloaking per the spec.

Demo of it working on VoiceOver (per @gonfunko -- note this was the menu variant rather than the list variant of the PR):

Screen Recording 2025-12-11 at 2 50 30 PM

Test Coverage

This has been manually tested with ChromeVox. No automated tests are needed as part of this experimental change.

Documentation

No new documentation changes are needed for this experimental change.

Additional Information

None.

Addresses some observed gaps in behaviors with connections. This is
unfortunately mainly a patch without fully understanding the deep issue
being avoided but it seems reasonable for the experimental branch.
It seems that the extra safety checks weren't actually needed.
More investigation and fixes are likely still needed.
@github-actions github-actions bot added the PR: feature Adds a feature label Dec 11, 2025
@github-actions github-actions bot added PR: feature Adds a feature and removed PR: feature Adds a feature labels Dec 11, 2025
@BenHenning
Copy link
Collaborator Author

@microbit-robert does this work for micro:bit? Will get this into review if you don't see any issues (and after #9449 goes in). It seems to be working well for me in ChromeVox and @gonfunko tested it on VoiceOver and didn't spot any issues so I'm hoping this addresses the root problem.

@github-actions github-actions bot added PR: feature Adds a feature and removed PR: feature Adds a feature labels Dec 11, 2025
@BenHenning BenHenning marked this pull request as ready for review December 12, 2025 02:45
@BenHenning BenHenning requested a review from a team as a code owner December 12, 2025 02:45
@BenHenning BenHenning requested review from gonfunko and removed request for a team December 12, 2025 02:45
@BenHenning
Copy link
Collaborator Author

PTAL @gonfunko. Apologies that this includes the changes in #9449. I will be merging this after that PR for sure, and if you don't review this before it's merged I'll make sure to update the conversation thread here with a note once the PR diff is clean.

@microbit-robert
Copy link
Collaborator

microbit-robert commented Dec 12, 2025

I have the following issue on Chrome, Firefox and Safari:

  • When navigating up from a statement block inside an if block, the VoiceOver cursor doesn't follow the focused element and the if block label is not read out. Update: the addition of this line appears to be the cause of the VO cursor becoming decoupled from the focused element during workspace navigation. Removing it addresses this problem.

In Safari and Firefox, the changes work well and the flyout navigation seems good.

I get some very odd VoiceOver issues when testing these changes on Chrome only.

  • When pressing 'T' to move into the toolbox, the toolbox categories are not read out, even when switching between them with up/down (this is what I experienced when I quickly attempted this change). Update: so, remove this line and everything works fine (but this is obviously incorrect). You can also change the role to generic or listbox or presumably almost anything else and it will work. I'm baffled.
    • Chrome (and other Chromium-based browsers) are important to us and we recommend Chrome for MakeCode (and for user testing) because it supports WebUSB which makes downloading a MakeCode program to a micro:bit easy. Safari does not support WebUSB.

I reset my VoiceOver settings to the defaults. I'll be even more confused if these issues can't be reproduced by anyone else - specifically the Chrome only issue. An alternative approach that does seem to work in Chrome, Firefox and Safari is to replace menu and menuitem with listbox and listitem.

Screen recording using VoiceOver and Chrome:
https://github.com/user-attachments/assets/14638a8c-7e03-42cb-ae4a-846fe928f3b3

I'll try and track down what changes specifically affect things in VoiceOver - comment has been updated.

@gonfunko
Copy link
Contributor

@microbit-robert I can repro the Safari issue, but the Chrome/VoiceOver one works fine for me even with the same block layout and key sequence as shown in your demo video oddly enough.

Comment on lines 711 to 715
// TODO: Optimize this.
return this.normalizeSeparators(contents).map((item) => {
// aria.setRole(item.getElement().getFocusableElement(), aria.Role.MENUITEM);
return item;
});
Copy link
Contributor

Choose a reason for hiding this comment

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

This appears to be a no-op at present, remove or uncomment the role setting?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Uh, this was a placeholder for testing and I did forget to remove it. Thanks for calling it out!

if (
nextConnection &&
nextConnection.canBeFocused() &&
nextConnection.type === ConnectionType.NEXT_STATEMENT
Copy link
Contributor

Choose a reason for hiding this comment

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

I think the check for type === ConnectionType.NEXT_STATEMENT is redundant given that we got the connection from the nextConnection field?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Good point--will remove this.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Also, moving comment to #9449 where it's actually needed.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Addressed in #9449.

@BenHenning
Copy link
Collaborator Author

Thanks @microbit-robert! That is very puzzling. I'm not opposed to switching to listitem and I was considering that originally. I think to some extent a list is even more generic than a menu, and the specification isn't super clear on when to pick one versus the other so I don't think it's strictly wrong to use list here, instead (that is, I'm not sure the extra semantic benefits of menu are worth risking bugs).

@BenHenning
Copy link
Collaborator Author

  • When navigating up from a statement block inside an if block, the VoiceOver cursor doesn't follow the focused element and the if block label is not read out. Update: the addition of this line appears to be the cause of the VO cursor becoming decoupled from the focused element during workspace navigation. Removing it addresses this problem.

This is an issue with #9449 and is actually rather concerning. I wasn't expecting the aria-owns declarations to actually impact behaviors, they were meant to just fix up the hierarchy. It's rather annoying that the VO cursor isn't following the focus given that's basically its job--I will need to try and figure out which specific association is breaking it since the hierarchy is more, not less, correct than before.

@BenHenning
Copy link
Collaborator Author

I was semi expecting the hierarchy changes from #9449 to cause more stability in the flyout for this PR but that may not actually be the case. I will try to decouple those changes so that this can go in independently as this is a much more pressing problem for the user test than #9449 (which is really just a stabilizing PR despite the regression).

@BenHenning BenHenning changed the title feat: Make Flyout an ARIA menu (experimental) [Blocked: #9449] feat: Make Flyout an ARIA menu (experimental) Dec 12, 2025
@github-actions github-actions bot added PR: feature Adds a feature and removed PR: feature Adds a feature labels Dec 12, 2025
Copy link
Collaborator Author

@BenHenning BenHenning left a comment

Choose a reason for hiding this comment

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

Quick self-review after detaching #9449.

Technically the branch name is now a lie.
@BenHenning BenHenning changed the title feat: Make Flyout an ARIA menu (experimental) feat: Make Flyout an ARIA list (experimental) Dec 12, 2025
@github-actions github-actions bot added PR: feature Adds a feature and removed PR: feature Adds a feature labels Dec 12, 2025
Copy link
Collaborator Author

@BenHenning BenHenning left a comment

Choose a reason for hiding this comment

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

Self-reviewed commit that changes this to a list (and makes the branch name a liar :) ).

@BenHenning
Copy link
Collaborator Author

@gonfunko could you perhaps take one more quick pass on the PR now that #9449 is detached and there are some other changes here?

@microbit-robert is this working well enough to merge or are more changes needed? I can do those on Monday if so.

@microbit-robert
Copy link
Collaborator

@BenHenning This now works well for me, thanks! There is some interesting numbering going on in VoiceOver with the list items in the flyout for full block fields that exist on their own (i.e., the first block in the Math flyout), but I think this is something that could be looked at separately. I would be happy if this got merged as is.

@BenHenning
Copy link
Collaborator Author

@BenHenning This now works well for me, thanks! There is some interesting numbering going on in VoiceOver with the list items in the flyout for full block fields that exist on their own (i.e., the first block in the Math flyout), but I think this is something that could be looked at separately. I would be happy if this got merged as is.

Could you file an issue for that separately @microbit-robert? Would be helpful to look at with a bit more context.

@BenHenning BenHenning merged commit bb342f9 into RaspberryPiFoundation:add-screen-reader-support-experimental Dec 15, 2025
13 of 14 checks passed
@BenHenning BenHenning deleted the make-flyout-a-menu branch December 15, 2025 18:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

PR: feature Adds a feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants