Skip to content

[a11y][web] Selecting menu items triggers a back navigation #134842

@Renzo-Olivares

Description

@Renzo-Olivares

Raised internally at b/299847356

Issue: Selecting a menu item with semantics enabled, for example through a pop up menu or dropdown menu, triggers a back navigation. This not only dismisses the menu, but also pops the next route from the navigator stack.

Expected: Selecting a menu item with semantics enabled dismisses the menu, but does not trigger another route to be popped from the navigator stack.

Bisected to engine roll: #131897
Bisected to engine commit: flutter/engine#43620

Minimal example for reproduction: https://dartpad.dev/?id=41045409a61245de472cb0083fc94742&channel=master

Screen.Recording.2023-09-15.at.1.44.04.PM.mov
Stack trace before change
dart-sdk/lib/_internal/js_dev_runtime/patch/core_patch.dart 941:28                get current
packages/flutter/src/material/popup_menu.dart 347:30                              handleTap
packages/flutter/src/material/ink_well.dart 1188:21                               handleTap
packages/flutter/src/gestures/recognizer.dart 275:24                              invokeCallback
packages/flutter/src/gestures/tap.dart 654:11                                     handleTapUp
packages/flutter/src/gestures/tap.dart 311:5                                      [_checkUp]
packages/flutter/src/gestures/tap.dart 244:7                                      handlePrimaryPointer
packages/flutter/src/gestures/recognizer.dart 630:9                               handleEvent
packages/flutter/src/gestures/pointer_router.dart 98:12                           [_dispatch]
packages/flutter/src/gestures/pointer_router.dart 143:9                           <fn>
dart-sdk/lib/_internal/js_dev_runtime/private/linked_hash_map.dart 21:13          forEach
packages/flutter/src/gestures/pointer_router.dart 141:17                          [_dispatchEventToRoutes]
packages/flutter/src/gestures/pointer_router.dart 127:7                           route
packages/flutter/src/gestures/binding.dart 488:19                                 handleEvent
packages/flutter/src/gestures/binding.dart 468:14                                 dispatchEvent
packages/flutter/src/rendering/binding.dart 439:11                                dispatchEvent
packages/flutter/src/gestures/binding.dart 413:7                                  [_handlePointerEventImmediately]
packages/flutter/src/gestures/binding.dart 376:5                                  handlePointerEvent
packages/flutter/src/gestures/binding.dart 323:7                                  [_flushPointerEventQueue]
packages/flutter/src/gestures/binding.dart 292:9                                  [_handlePointerDataPacket]
lib/_engine/engine/platform_dispatcher.dart 1295:13                               invoke1
lib/_engine/engine/platform_dispatcher.dart 273:5                                 invokeOnPointerDataPacket
lib/_engine/engine/pointer_binding.dart 168:39                                    [_onPointerData]
lib/_engine/engine/pointer_binding.dart 791:20                                    <fn>
lib/_engine/engine/pointer_binding.dart 720:14                                    <fn>
lib/_engine/engine/pointer_binding.dart 317:16                                    loggedHandler
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart 574:37  _checkAndCall
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart 579:39  dcall
Stack trace after change
dart-sdk/lib/_internal/js_dev_runtime/patch/core_patch.dart 941:28                get current
packages/flutter/src/widgets/navigator.dart 2525:30                               maybePop
packages/flutter/src/widgets/modal_barrier.dart 228:21                            handleDismiss
packages/flutter/src/rendering/proxy_box.dart 4492:24                             [_performTap]
packages/flutter/src/semantics/semantics.dart 3541:14                             <fn>
packages/flutter/src/semantics/semantics.dart 3358:14                             performAction
packages/flutter/src/rendering/binding.dart 447:64                                performSemanticsAction
packages/flutter/src/semantics/binding.dart 119:5                                 [_handleSemanticsActionEvent]
lib/_engine/engine/platform_dispatcher.dart 1295:13                               invoke1
lib/_engine/engine/platform_dispatcher.dart 1173:5                                invokeOnSemanticsAction
lib/_engine/engine/pointer_binding.dart 263:43                                    onClick
lib/_engine/engine/semantics/tappable.dart 34:22                                  <fn>
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart 574:37  _checkAndCall
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart 579:39  dcall
dart-sdk/lib/_internal/js_dev_runtime/patch/core_patch.dart 941:28                get current
packages/flutter/src/material/popup_menu.dart 347:30                              handleTap
packages/flutter/src/material/ink_well.dart 1188:21                               handleTap
packages/flutter/src/material/ink_well.dart 861:5                                 simulateTap
packages/flutter/src/rendering/proxy_box.dart 4492:24                             [_performTap]
packages/flutter/src/semantics/semantics.dart 3539:14                             <fn>
packages/flutter/src/semantics/semantics.dart 3357:14                             performAction
packages/flutter/src/rendering/binding.dart 447:64                                performSemanticsAction

From the stack trace it looks like a second semantics action is being dispatched and that is causing a second route to be popped from the navigator stack. The first pop that happens in PopUpMenu is expected

void handleTap() {
// Need to pop the navigator first in case onTap may push new route onto navigator.
Navigator.pop<T>(context, widget.value);
widget.onTap?.call();
}
, but the second pop that happens in ModalBarrier
void handleDismiss() {
if (dismissible) {
if (onDismiss != null) {
onDismiss!();
} else {
Navigator.maybePop(context);
}
} else {
SystemSound.play(SystemSoundType.alert);
}
}
is not expected.

Metadata

Metadata

Assignees

Labels

P1High-priority issues at the top of the work lista: accessibilityAccessibility, e.g. VoiceOver or TalkBack. (aka a11y)c: regressionIt was better in the past than it is nowf: material designflutter/packages/flutter/material repository.frameworkflutter/packages/flutter repository. See also f: labels.platform-webWeb applications specificallyteam-designOwned by Design Languages teamtriaged-designTriaged by Design Languages team

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions