Repository navigation
[web] Omit group role on menu scrollables and assign region role to named routes - #192965
Conversation
…le to named routes
When PopupMenuButton, MenuAnchor, or DropdownButton renders a menu on the web, its items are wrapped in an intermediate SingleChildScrollView (SemanticScrollable with role='group') while SemanticMenu sets aria-owns directly to the descendant menuItem nodes. Leaving role='group' on the unlabeled intermediate scrollable causes screen readers (such as VoiceOver on macOS) to count the scrollable container as an extra first item ('menu, N+1 items', announcing item 1 as '2 of N+1'). Setting role='none' on unlabeled intermediate SemanticScrollable containers inside SemanticMenu and SemanticMenuBar eliminates the off-by-one item count while preserving DOM scroll behavior.
Additionally, when a SemanticRoute sets namesRoute: true (applying aria-label to <flt-semantics>), set role='region' so self-labeled routes do not violate WAI-ARIA aria-prohibited-attr on generic elements.
Fixes flutter#190661
…ate menu container base
There was a problem hiding this comment.
Code Review
This pull request refactors menu semantics by introducing a shared _SemanticMenuContainerBase class, updates SemanticRoute to set its ARIA role to 'region' when it has a route name and label, and configures SemanticScrollable to set its ARIA role to 'none' when unlabeled and nested within a menu. The review feedback highlights a redundant check in menus.dart that duplicates the role-setting logic already handled by SemanticScrollable, recommending its removal to maintain a single source of truth.
|
CI had a failure that stopped further tests from running. We need to investigate to determine the root cause. SHA at time of execution: 88ec987. Possible causes:
A blank commit, or merging to head, will be required to resume running CI for this PR. Error Details: Stack trace: |
flutter-zl
left a comment
There was a problem hiding this comment.
I deployed both before and after change app to firebase. DropdownButton still announces N+1 items.
Before: https://flutter-demo-65-before.web.app, After: https://flutter-demo-65-after.web.app
The dropdown menu is a ListView, which the framework splits into two semantics nodes: an outer node with no config and an inner scrollable node. The PR only sets role="none" on the inner one, so the outer node shows up as a generic element and is still the menu's first child. PopupMenuButton is fixed because SingleChildScrollView produces only one node.
…d Changes Requested (Resolved) (#124) - Copy `reviewAuthors`, `approvedReviewers`, `lastAuthorReviewAt`, `lastCommitAt`, and `lastUnrequestedReviewAt` when `_attachLocalStatus` constructs the enriched `GhPr` instance in `runGhView`. - Require `hasAuthorRespondedSinceLastReview` before classifying `CHANGES_REQUESTED` with `areThreadsResolved` as `Changes Requested (Resolved)` / `Re-review Needed (threads resolved)`, so top-level `CHANGES_REQUESTED` reviews on PRs with older resolved bot threads (e.g. `flutter/flutter#192965`) remain `🔴 Changes Requested (@Reviewer)`. - Set `maxPageSize: 15` in `fetchOpenPullRequests` to avoid GitHub GraphQL `HTTP 502` gateway timeouts on dense PR pages.
When DropdownButton renders a ListView inside a menu, the framework splits the ListView into an outer unlabeled GenericRole container node and an inner SemanticScrollable node. Setting role='none' on unlabeled, non-tappable GenericRole nodes with a menu/menuBar ancestor prevents the browser from exposing the outer wrapper as an extra generic child of role='menu'.
…-pr3-menu-route-roles
|
Thanks for testing and catching that on You nailed the root cause: Updated |
flutter-zl
left a comment
There was a problem hiding this comment.
Great. I tested with https://flutter-demo-65-after.web.app/. it works. Thanks for fixing this issue.
Before: https://flutter-demo-65-before.web.app, After: https://flutter-demo-65-after.web.app
…amed routes (flutter#192965) ## Description Fixes two web accessibility ARIA role issues in `lib/web_ui`: 1. **VoiceOver item count off-by-one in `PopupMenuButton`, `MenuAnchor`, and `DropdownButton` (`flutter#190661`)**: When a menu renders on the web, its items are wrapped in an intermediate `SingleChildScrollView` (`SemanticScrollable`, which sets `role="group"` in its constructor) while `SemanticMenu` / `SemanticMenuBar` sets `aria-owns` directly to the descendant `menuItem` nodes. Leaving `role="group"` on the unlabeled intermediate scrollable causes WebKit/VoiceOver to count the scrollable container as child `1` alongside the `N` `aria-owns` `menuitem`s (`"menu, N+1 items"`, announcing item 1 as `"2 of N+1"`). Setting `role="none"` on unlabeled intermediate `SemanticScrollable` containers inside `SemanticMenu` and `SemanticMenuBar` eliminates the off-by-one item count while preserving DOM scroll behavior. 2. **Valid ARIA role for self-labeled `SemanticRoute` (`aria-prohibited-attr`, http://b/462008723, http://b/461982793, http://b/460641753)**: When `SemanticRoute` has `namesRoute: true` (setting `aria-label` on `<flt-semantics>`), it previously omitted the `role` attribute (`role="generic"`), violating WAI-ARIA 1.2 `aria-prohibited-attr` (`aria-label` is prohibited on generic elements). `SemanticRoute.update()` now sets `role="region"` when `semanticsObject.namesRoute` is true. Fixes flutter#190661 Fixes http://b/462008723 Fixes http://b/461982793 Fixes http://b/460641753 ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing.
…amed routes (flutter#192965) ## Description Fixes two web accessibility ARIA role issues in `lib/web_ui`: 1. **VoiceOver item count off-by-one in `PopupMenuButton`, `MenuAnchor`, and `DropdownButton` (`flutter#190661`)**: When a menu renders on the web, its items are wrapped in an intermediate `SingleChildScrollView` (`SemanticScrollable`, which sets `role="group"` in its constructor) while `SemanticMenu` / `SemanticMenuBar` sets `aria-owns` directly to the descendant `menuItem` nodes. Leaving `role="group"` on the unlabeled intermediate scrollable causes WebKit/VoiceOver to count the scrollable container as child `1` alongside the `N` `aria-owns` `menuitem`s (`"menu, N+1 items"`, announcing item 1 as `"2 of N+1"`). Setting `role="none"` on unlabeled intermediate `SemanticScrollable` containers inside `SemanticMenu` and `SemanticMenuBar` eliminates the off-by-one item count while preserving DOM scroll behavior. 2. **Valid ARIA role for self-labeled `SemanticRoute` (`aria-prohibited-attr`, http://b/462008723, http://b/461982793, http://b/460641753)**: When `SemanticRoute` has `namesRoute: true` (setting `aria-label` on `<flt-semantics>`), it previously omitted the `role` attribute (`role="generic"`), violating WAI-ARIA 1.2 `aria-prohibited-attr` (`aria-label` is prohibited on generic elements). `SemanticRoute.update()` now sets `role="region"` when `semanticsObject.namesRoute` is true. Fixes flutter#190661 Fixes http://b/462008723 Fixes http://b/461982793 Fixes http://b/460641753 ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing.
…#13060) Manual roll Flutter from 4fcd90be0045 to c5a061b18fa2 (222 revisions) Manual roll requested by [email protected] flutter/flutter@4fcd90b...c5a061b 2026-09-28 [email protected] [cross imports] navigator_test.dart (flutter/flutter#190954) 2026-09-28 [email protected] Revert: Reland: Only render views that need to be rendered (flutter/flutter#193360) 2026-09-28 [email protected] ci(bringup): android_intent_security_test is green (flutter/flutter#193469) 2026-09-28 [email protected] Sync CHANGELOG.md from stable (flutter/flutter#193020) 2026-09-28 [email protected] Roll Fuchsia Linux SDK from ukukV5lEkKabtOATk... to QdgqP02_cYpRQQQNN... (flutter/flutter#193454) 2026-09-28 [email protected] Roll pub packages (flutter/flutter#193460) 2026-09-28 [email protected] Un-nest sceneBuildDuration and windowRenderDuration in web SceneBuilderRecorder (flutter/flutter#193260) 2026-09-28 [email protected] Fix unresolved doc comment references in dev/integration_tests and dev/benchmarks (flutter/flutter#193433) 2026-09-28 [email protected] Roll Packages from e55e7ac to ba0364a (9 revisions) (flutter/flutter#193450) 2026-09-28 [email protected] [tool] Require explicit dependency injection for FlutterDevice and FlutterDevice.create (flutter/flutter#192830) 2026-09-28 [email protected] Roll pub packages (flutter/flutter#193442) 2026-09-28 [email protected] [flutter_tools] Include data assets from hooks when pubspec.yaml is empty (flutter/flutter#193434) 2026-09-28 [email protected] Roll pub packages (flutter/flutter#193438) 2026-09-28 [email protected] Fix unresolved doc comment references in Material and Cupertino (flutter/flutter#193283) 2026-09-28 [email protected] Fix doc references to Material and Cupertino in the widgets library and its tests (flutter/flutter#193334) 2026-09-26 [email protected] wasm: enforce WasmGC opt-in capability checks and Firefox < 147 guard (flutter/flutter#193180) 2026-09-26 [email protected] [Android] Refuse external setters of engine entrypoint and cached engine arguments via `Intent`s (flutter/flutter#190249) 2026-09-26 [email protected] [web] Unskip TextPainter.getWordBoundary test (flutter/flutter#193378) 2026-09-26 [email protected] Specify non-obvious types in pattern variable declarations (flutter/flutter#192632) 2026-09-26 [email protected] Removes feedback loop from advanced filters without offscreen msaa and framebufferfetch (flutter/flutter#193306) 2026-09-26 [email protected] [web] Unskip 8 passing image tests in painting and rendering (flutter/flutter#193377) 2026-09-26 [email protected] Revert: Allow resetting test invariants in `addTearDown` (flutter/flutter#193383) 2026-09-25 [email protected] [tool] Migrate CoverageCollector to modular dependency injection (flutter/flutter#192924) 2026-09-25 [email protected] Fix more unresolved doc comment references (flutter/flutter#193336) 2026-09-25 [email protected] Allow resetting test invariants in `addTearDown` (flutter/flutter#192082) 2026-09-25 [email protected] [a11y] Add a semantics role for slider (flutter/flutter#193324) 2026-09-25 [email protected] Fix plugin tests after Pigeon plugin template changes (flutter/flutter#193302) 2026-09-25 [email protected] [Android 17] Bump Standard Test Apps in flutter/flutter to AGP 9.3.1 (flutter/flutter#193263) 2026-09-25 [email protected] SSBO-based gradients in UberSDF (flutter/flutter#192962) 2026-09-25 [email protected] [Linux] Handle FlView being destroyed before rendering is complete. (flutter/flutter#193268) 2026-09-25 [email protected] [flutter_tools] Handle Windows reserved characters in test target path (flutter/flutter#191900) 2026-09-25 [email protected] docs(tools): nit: say hook/build.dart in CMake native assets comment (flutter/flutter#192205) 2026-09-25 [email protected] [web] Enable Firefox Skwasm UI CI suites, configure COI configs, and fail fast on loader rejections (flutter/flutter#193187) 2026-09-25 [email protected] [Android 17] Bumped Engine Dependencies to 9.3.1 (flutter/flutter#193265) 2026-09-25 [email protected] [web] Omit group role on menu scrollables and assign region role to named routes (flutter/flutter#192965) 2026-09-25 [email protected] Roll Skia from 8eedeed98e79 to f441ca223b2b (5 revisions) (flutter/flutter#193353) 2026-09-25 [email protected] Roll Fuchsia Linux SDK from EbPpoJW-Lnsu-8dyZ... to ukukV5lEkKabtOATk... (flutter/flutter#193326) 2026-09-25 [email protected] Roll Packages from 431ea69 to e55e7ac (6 revisions) (flutter/flutter#193351) 2026-09-25 [email protected] Support DynamicLibrary.codeAsset in Flutter (flutter/flutter#188947) 2026-09-25 [email protected] Roll Dart SDK from 75d9e87d4e3d to 0e7642b85457 (1 revision) (flutter/flutter#193346) 2026-09-25 [email protected] Exclude iOS PRs from macOS link (flutter/flutter#193315) 2026-09-25 [email protected] Roll Skia from 6357608543ec to 8eedeed98e79 (4 revisions) (flutter/flutter#193341) 2026-09-25 [email protected] Roll Dart SDK from d3aedb186aab to 75d9e87d4e3d (3 revisions) (flutter/flutter#193335) 2026-09-25 [email protected] Cache the paint offset adjusted line metrics in TextPainter (flutter/flutter#191223) ...
Description
Fixes two web accessibility ARIA role issues in
lib/web_ui:PopupMenuButton,MenuAnchor, andDropdownButton(#190661): When a menu renders on the web, its items are wrapped in an intermediateSingleChildScrollView(SemanticScrollable, which setsrole="group"in its constructor) whileSemanticMenu/SemanticMenuBarsetsaria-ownsdirectly to the descendantmenuItemnodes. Leavingrole="group"on the unlabeled intermediate scrollable causes WebKit/VoiceOver to count the scrollable container as child1alongside theNaria-ownsmenuitems ("menu, N+1 items", announcing item 1 as"2 of N+1"). Settingrole="none"on unlabeled intermediateSemanticScrollablecontainers insideSemanticMenuandSemanticMenuBareliminates the off-by-one item count while preserving DOM scroll behavior.SemanticRoute(aria-prohibited-attr, http://b/462008723, http://b/461982793, http://b/460641753): WhenSemanticRoutehasnamesRoute: true(settingaria-labelon<flt-semantics>), it previously omitted theroleattribute (role="generic"), violating WAI-ARIA 1.2aria-prohibited-attr(aria-labelis prohibited on generic elements).SemanticRoute.update()now setsrole="region"whensemanticsObject.namesRouteis true.Fixes #190661
Fixes http://b/462008723
Fixes http://b/461982793
Fixes http://b/460641753
Pre-launch Checklist
///).