Skip to content

Conversation

@flutter-zl
Copy link
Contributor

@flutter-zl flutter-zl commented Oct 13, 2025

Implements engine-side declarative pointer event handling for semantics.

Framework-side to be implemented in next PR.

Fixes #149001.

Before change
https://dialog-dismiss-before.web.app/

Click on the "Show Dialog" button.
Click anywhere inside the dialog that is not a form field.
Observe the dialog being dismissed.

After change
https://dialog-dimiss-after.web.app/

Click on the "Show Dialog" button.
Click anywhere inside the dialog that is not a form field.
Observe the dialog not dismissed.

@github-actions github-actions bot added engine flutter/engine related. See also e: labels. a: accessibility Accessibility, e.g. VoiceOver or TalkBack. (aka a11y) platform-web Web applications specifically labels Oct 13, 2025
Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request effectively fixes an issue where dialogs on the web could be prematurely dismissed when semantics are enabled. The root cause was that non-interactive semantic leaf nodes were incorrectly intercepting pointer events.

The fix introduces a more nuanced policy for determining which semantic nodes accept pointer events:

  1. Route-scoped containers (like dialogs) now accept pointer events to function as a barrier.
  2. Leaf nodes only accept pointer events if they are interactive (e.g., buttons, text fields).

This change is well-supported by a comprehensive set of new unit tests that verify the behavior of various interactive and non-interactive nodes. The implementation is clear and directly addresses the problem. I have a couple of suggestions to further improve robustness and test maintainability.

Comment on lines 604 to 610
return semanticsObject.isTappable ||
semanticsObject.isButton ||
semanticsObject.isCheckable ||
semanticsObject.flags.isTextField ||
semanticsObject.flags.isLink ||
semanticsObject.flags.isSlider ||
semanticsObject.isIncrementable;
Copy link
Contributor

Choose a reason for hiding this comment

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

All of these have their own Semantics role or behavior (except isSlider [1]). Let's override the acceptsPointerEvents in the corresponding classes.

[1] It looks like semantic sliders are not implemented? So let's not worry about it now.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Implemented engine-side declarative pointer event handling for semantics based on discussion. Please review.

@flutter-zl flutter-zl requested a review from mdebbar October 15, 2025 05:46
flutter-zl added a commit that referenced this pull request Oct 17, 2025
Enhanced acceptsPointerEvents with:
- Multi-tier policy documentation (4 tiers)
- Tier 1: Explicit behaviors (Tappable, TextField, etc.)
- Tier 2: Framework declaration (TODO for future SemanticsHitTestBehavior)
- Tier 3: Route-scoped containers fallback (current fix)
- Tier 4: Default transparent leaf nodes

The fallback ensures:
- Immediate bug fix for dialog dismissal
- Backward compatibility during framework transition
- Support for third-party packages
- Graceful degradation for custom widgets

Prepared for future framework PR that will add SemanticsHitTestBehavior
enum for declarative control over pointer event handling.

Related: #149001
Discussion: #176974
@flutter-zl flutter-zl changed the title Fix premature dialog dismissal on Web when semantics enabled Implements engine-side declarative pointer event handling for semantics. Oct 17, 2025
@flutter-zl flutter-zl requested a review from chunhtai October 17, 2025 17:50
@@ -1156,6 +1156,34 @@ enum Tristate {
}
}

/// Describes how a semantic node should behave during hit testing.
///
/// This enum is used by the web engine to determine whether semantic elements
Copy link
Contributor

Choose a reason for hiding this comment

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

This will likely to be used by other platform as well, we should make the language platform neutral
#177025
#177024

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for reviewing. I updated the PR accordingly.

enum SemanticsHitTestBehavior {
/// The semantic element is opaque to hit testing, consuming any pointer
/// events within its bounds and preventing them from reaching elements
/// behind it.
Copy link
Contributor

Choose a reason for hiding this comment

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

is this blocking child or sibling in hittest order? or both? should document this more clearly

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for reviewing. I updated the PR accordingly.

@@ -1792,12 +1820,20 @@ abstract class SemanticsUpdateBuilder {
/// not use this argument should use other ways to communicate validation
/// errors to the user, such as embedding validation error text in the label.
///
/// The `hitTestBehavior` describes how this node should behave during hit
/// testing. If null, the platform will infer appropriate behavior based on
/// other semantic properties. This is primarily used by the web platform to
Copy link
Contributor

Choose a reason for hiding this comment

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

same for the comment here, should be platform neutral

Copy link
Contributor

Choose a reason for hiding this comment

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

what's the infer behavior? do they inherited from the parent?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for reviewing. I updated the PR accordingly.

@@ -1792,12 +1820,20 @@ abstract class SemanticsUpdateBuilder {
/// not use this argument should use other ways to communicate validation
/// errors to the user, such as embedding validation error text in the label.
///
/// The `hitTestBehavior` describes how this node should behave during hit
/// testing. If null, the platform will infer appropriate behavior based on
Copy link
Contributor

Choose a reason for hiding this comment

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

instead of using null, consider give it a enum SemanticsHitTestBehavior.defer and makes it the default

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for reviewing. I updated the PR accordingly.

@@ -1913,6 +1949,7 @@ base class _NativeSemanticsUpdateBuilder extends NativeFieldWrapperClass1
SemanticsRole role = SemanticsRole.none,
required List<String>? controlsNodes,
SemanticsValidationResult validationResult = SemanticsValidationResult.none,
SemanticsHitTestBehavior? hitTestBehavior,
Copy link
Contributor

Choose a reason for hiding this comment

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

should remove nullable and make required

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for reviewing. I updated the PR accordingly.

///
/// This is the default behavior for non-interactive semantic nodes.
///
/// On the web, this results in `pointer-events: none` CSS property.
Copy link
Contributor

Choose a reason for hiding this comment

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

In framework transparent means this node receives hittest, but won't block the silbing and child behind it from receiving hittest

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for reviewing. I updated the PR accordingly.

Copy link
Contributor

Choose a reason for hiding this comment

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

In framework transparent means this node receives hittest, but won't block the silbing and child behind it from receiving hittest

I think you meant "translucent"?

/// How to behave during hit tests.
enum HitTestBehavior {
/// Targets that defer to their children receive events within their bounds
/// only if one of their children is hit by the hit test.
deferToChild,
/// Opaque targets can be hit by hit tests, causing them to both receive
/// events within their bounds and prevent targets visually behind them from
/// also receiving events.
opaque,
/// Translucent targets both receive events within their bounds and permit
/// targets visually behind them to also receive events.
translucent,
}

"transparent" is defined in platform view behaviors:

enum PlatformViewHitTestBehavior {
/// Opaque targets can be hit by hit tests, causing them to both receive
/// events within their bounds and prevent targets visually behind them from
/// also receiving events.
opaque,
/// Translucent targets both receive events within their bounds and permit
/// targets visually behind them to also receive events.
translucent,
/// Transparent targets don't receive events within their bounds and permit
/// targets visually behind them to receive events.
transparent,
}

  • "opaque" matches pointer-events: all on the web.
  • "transparent" matches pointer-events: none on the web.
  • "translucent" (which is what you're describing) is not possible on web AFAICT.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good catch. I updated the PR accordingly.

///
/// The decision follows a multi-tier policy:
///
/// **Tier 1: Explicit Behaviors** - Behaviors attached to this role can
Copy link
Contributor

Choose a reason for hiding this comment

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

Declaration should probably come first before this. Also I think you meant Implicit behaviors? since the behavior is inferred from semantics behavior/role

Copy link
Contributor

Choose a reason for hiding this comment

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

also ideally we should infer the SemanticsHitTestBehavior from the framework side if not provided. That way the platform just need to deal with SemanticsHitTestBehavior

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for reviewing. I updated the PR accordingly.

Copy link
Contributor

@mdebbar mdebbar Oct 20, 2025

Choose a reason for hiding this comment

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

Declaration should probably come first before this.

This part of the comment was not addressed. When the framework says the node is transparent, we should treat it as transparent. It becomes really confusing when users set a button to transparent and notice that the button is still receiving clicks and blocking hit testing.

If we think it's a bad idea to allow interactive nodes to be transparent, then we should make that state illegal at the framework level. IMO the engine should just follow what the framework dictates.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good catch. I thought it is about code style. I updated the PR accordingly.

/// [ui.SemanticsHitTestBehavior], it will be respected here. This allows
/// declarative control over pointer event handling from the framework layer.
///
/// **Tier 3: Route-Scoped Containers** - Containers with [scopesRoute] set
Copy link
Contributor

Choose a reason for hiding this comment

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

This should be handled in framework by wrapping ModalRoute with SemanticsHitTestBehavior

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You're right that framework should handle this. Our architecture fully supports that. When framework provides explicit values, engine just executes them (Tier 1). Engine inference is only a backward-compatible fallback (Tier 2) because popular packages like awesome_dialog don't know about SemanticsHitTestBehavior yet. Engine inference means they work immediately.

/// preventing clicks from escaping to underlying modal barriers. This is
/// the current fix for issue #149001.
///
/// **Tier 4: Default Transparent** - Leaf nodes without interactive behaviors
Copy link
Contributor

Choose a reason for hiding this comment

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

we could also handle this on the framework side by inferring SemanticsHitTestBehavior if not provided

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You're right that framework should handle this. Our architecture fully supports that. When framework provides explicit values, engine just executes them (Tier 1). Engine inference is only a backward-compatible fallback (Tier 2) because popular packages like awesome_dialog don't know about SemanticsHitTestBehavior yet. Engine inference means they work immediately.

@flutter-zl flutter-zl requested a review from chunhtai October 20, 2025 19:07
@github-actions github-actions bot added the framework flutter/packages/flutter repository. See also f: labels. label Oct 20, 2025
/// Platform implementations:
/// * On the web, this results in `pointer-events: none` CSS property.
///
/// This is the default behavior for non-interactive semantic nodes when the
Copy link
Contributor

@chunhtai chunhtai Oct 20, 2025

Choose a reason for hiding this comment

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

this paragraph should probably be in defer enum instead, and also mention this is web's default behavior if we want to include this info. (we don't know what other platform will do yet)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Great suggestion. I updated the documentation.

}

@override
bool get acceptsPointerEvents => true;
Copy link
Contributor

Choose a reason for hiding this comment

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

This is unfortunate name collisions, should make it something like shouldAcceptsPointerEvents.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

acceptsPointerEvents already exists in abstract class SemanticBehavior and abstract class SemanticBehavior. Please check https://github.com/flutter/flutter/blob/master/engine/src/flutter/lib/web_ui/lib/src/engine/semantics/semantics.dart. do we want to change one of them to shouldAcceptsPointerEvents?

Copy link
Contributor

Choose a reason for hiding this comment

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

we should rename this getter for every classes, it shouldn't be a problem since these are not public

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for the explanation. I updated the code.

/// - Route-scoped containers (dialogs, bottom sheets)
/// - Default transparent for non-interactive leaf nodes
///
/// This approach allows framework full control when specified, with intelligent
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
/// This approach allows framework full control when specified, with intelligent
/// This approach allows framework full control when specified, with reasonable

Copy link
Contributor

Choose a reason for hiding this comment

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

should tune down the tone a bit

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Great suggestion. I updated the documentation.

case ui.SemanticsHitTestBehavior.defer:
// This case should never be reached because defer is handled in
// acceptsPointerEvents before calling this method.
assert(false, 'defer should be handled by _inferAcceptsPointerEvents');
Copy link
Contributor

@chunhtai chunhtai Oct 20, 2025

Choose a reason for hiding this comment

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

consider inline this switch case directly in acceptsPointerEvents body so that we don't need this assert

Copy link
Contributor Author

@flutter-zl flutter-zl Oct 21, 2025

Choose a reason for hiding this comment

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

Great suggestion. I updated the code.


/// Infers whether pointer events should be accepted based on semantic properties.
///
/// This method is called when [ui.SemanticsHitTestBehavior.defer] is set,
Copy link
Contributor

Choose a reason for hiding this comment

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

consider remove this paragraph and use assert(hitTestBehavior == ui.SemanticsHitTestBehavior.defer) to explain the assumption

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Great suggestion. I updated the code.

// from passing through to the modal barrier underneath.
if (semanticsObject.hasChildren) {
return false;
return semanticsObject.scopesRoute;
Copy link
Contributor

Choose a reason for hiding this comment

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

this should be set from the framework side instead of using inferring here. The reason being that we don't want every platform has to duplicate this logic. ideally, platform inferring should be as less as possible.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The intention is to let packages like https://pub.dev/packages/awesome_dialog which has not implemented our change to have the fix.

Copy link
Contributor

Choose a reason for hiding this comment

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

In general, it will be their responsibility to opt in, but in this case as long as this is wrapped in

_modalScope = OverlayEntry(

All the route/dialog should get this automaticially

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for the explanation. I updated the code.

@flutter-zl flutter-zl requested a review from chunhtai October 21, 2025 18:54
@flutter-zl flutter-zl requested a review from chunhtai October 23, 2025 18:23
Copy link
Contributor

@chunhtai chunhtai left a comment

Choose a reason for hiding this comment

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

LGTM

Comment on lines 77 to 79
ui.SemanticsHitTestBehavior.opaque => true,
ui.SemanticsHitTestBehavior.transparent => false,
_ => true,
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
ui.SemanticsHitTestBehavior.opaque => true,
ui.SemanticsHitTestBehavior.transparent => false,
_ => true,
ui.SemanticsHitTestBehavior.transparent => false,
_ => true,

Copy link
Contributor

Choose a reason for hiding this comment

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

missed this

Copy link
Contributor Author

Choose a reason for hiding this comment

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

good catch. Updated.

@flutter-zl flutter-zl added this pull request to the merge queue Oct 23, 2025
Merged via the queue into master with commit 26766ac Oct 23, 2025
188 of 189 checks passed
@flutter-zl flutter-zl deleted the dialog_1009 branch October 23, 2025 21:59
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Oct 24, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Oct 24, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Oct 24, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Oct 24, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Oct 24, 2025
auto-submit bot pushed a commit to flutter/packages that referenced this pull request Oct 24, 2025
Roll Flutter from 75004a639ae4 to cb18290fa45e (48 revisions)

flutter/flutter@75004a6...cb18290

2025-10-24 [email protected] Remove unnecessary `deprecated` withOpacity in `text_button.0.dart‎` in examples (flutter/flutter#177374)
2025-10-24 [email protected] Roll Packages from 9ec29b6 to 53d6138 (3 revisions) (flutter/flutter#177502)
2025-10-24 [email protected] Roll Dart SDK from d3248b00f545 to a0480f399f8f (1 revision) (flutter/flutter#177498)
2025-10-24 [email protected] Roll Skia from a47931d09585 to 3ed332b77bec (3 revisions) (flutter/flutter#177487)
2025-10-24 [email protected] Roll Abseil to Chromium's 5b92b04a2e (based on Abseil commit fc4481e968) (flutter/flutter#177059)
2025-10-24 98614782+auto-submit[bot]@users.noreply.github.com Reverts "Reverts "Enhance PR template with changelog and impact details (#177333)" (#177468)" (flutter/flutter#177499)
2025-10-24 [email protected] Document DropdownMenu showTrailingIcon and decorationBuilder interaction (flutter/flutter#177488)
2025-10-24 [email protected] Roll Dart SDK from 4a65fb890852 to d3248b00f545 (1 revision) (flutter/flutter#177486)
2025-10-24 [email protected] Fix bottom sheet Semantics route label for mismatched platforms (flutter/flutter#177094)
2025-10-24 [email protected] Roll Skia from eba11de00d5b to a47931d09585 (5 revisions) (flutter/flutter#177481)
2025-10-24 [email protected] Fix Dialog Semantics label and flags for mismatched platforms (flutter/flutter#176781)
2025-10-24 [email protected] Fix drawer Semantics for mismatched platforms (flutter/flutter#177095)
2025-10-24 [email protected] Roll Dart SDK from f7751ccea102 to 4a65fb890852 (2 revisions) (flutter/flutter#177480)
2025-10-23 [email protected] Change the root path of the license crawl to engine/src (flutter/flutter#177352)
2025-10-23 [email protected] [Material] Change default mouse cursor of buttons to basic arrow instead of click (except on web) (flutter/flutter#171796)
2025-10-23 [email protected] [Desktop] Propagate SemanticsNode::identifier to AXPlatformNodeDelegate::AuthorUniqueId (flutter/flutter#175405)
2025-10-23 [email protected] Roll Skia from 59ef57f4104e to eba11de00d5b (5 revisions) (flutter/flutter#177461)
2025-10-23 [email protected] Roll customer tests (flutter/flutter#177409)
2025-10-23 [email protected] Update CHANGELOG 3.35.7 notes (flutter/flutter#177463)
2025-10-23 [email protected] Marks Mac module_uiscene_test_ios to be unflaky (flutter/flutter#177378)
2025-10-23 [email protected] Allow empty dart defines in `flutter assemble` (flutter/flutter#177198)
2025-10-23 [email protected] Roll Packages from d113bbc to 9ec29b6 (12 revisions) (flutter/flutter#177455)
2025-10-23 [email protected] Implements engine-side declarative pointer event handling for semantics. (flutter/flutter#176974)
2025-10-23 [email protected] Fix the platform name of the windowing_test target for macOS in ci.yaml (flutter/flutter#177472)
2025-10-23 98614782+auto-submit[bot]@users.noreply.github.com Reverts "Enhance PR template with changelog and impact details (#177333)" (flutter/flutter#177468)
2025-10-23 [email protected] Change Flutter APIs to use spans (flutter/flutter#177272)
2025-10-23 [email protected] Roll Dart SDK from 020988602772 to f7751ccea102 (4 revisions) (flutter/flutter#177449)
2025-10-23 [email protected] [macOS] Implement regular window (flutter/flutter#176361)
2025-10-23 [email protected] Enhance PR template with changelog and impact details (flutter/flutter#177333)
2025-10-23 [email protected] Roll Skia from 6e6acf6644ef to 59ef57f4104e (2 revisions) (flutter/flutter#177436)
2025-10-23 [email protected] Add directional static members to AlignmentGeometry. (flutter/flutter#176571)
2025-10-23 [email protected] Roll ICU from 1b2e3e8a421e to ff35c4f9df23 (5 revisions) (flutter/flutter#177434)
2025-10-23 [email protected] Adds a new CI build for Linux host DDM-enabled artifacts (flutter/flutter#177252)
2025-10-23 [email protected] Roll Skia from 920cdcadd74c to 6e6acf6644ef (1 revision) (flutter/flutter#177432)
2025-10-23 [email protected] Roll Skia from 8cd449e4953b to 920cdcadd74c (6 revisions) (flutter/flutter#177426)
2025-10-23 [email protected] Added ahem license (flutter/flutter#177423)
2025-10-23 [email protected] Roll Dart SDK from 75f6ccb9bdc5 to 020988602772 (1 revision) (flutter/flutter#177421)
2025-10-23 [email protected] [web] Set `pointer-events: none` for img-element-backed images (flutter/flutter#177418)
2025-10-22 [email protected] Remove the x64 version of build_ios_framework_module_test (flutter/flutter#177136)
2025-10-22 [email protected] Fix accessibility events not being correctly translated to ATK (flutter/flutter#176991)
2025-10-22 [email protected] Roll Skia from b55bd60ed95b to 8cd449e4953b (8 revisions) (flutter/flutter#177405)
2025-10-22 [email protected] Roll Dart SDK from c23010c4f9e6 to 75f6ccb9bdc5 (4 revisions) (flutter/flutter#177399)
2025-10-22 [email protected] Fixes crash when adding and removing mulitple page-based route (flutter/flutter#177338)
2025-10-22 [email protected] Move child parameter to end of RefreshIndicator constructor (flutter/flutter#177019)
2025-10-22 [email protected] refactor: migrate OpenUpwardsPageTransitionsBuilder to widgets (flutter/flutter#177080)
2025-10-22 [email protected] Delete stray 'text' file (flutter/flutter#177355)
...
github-merge-queue bot pushed a commit that referenced this pull request Nov 18, 2025
…pply to ModalRoute (#177570)

Fix premature dialog dismissal on Flutter Web when semantics are enabled
by correctly propagating hitTestBehavior through the semantics pipeline
and declaring modal routes as opaque to pointer events.

Before change
https://dialog-dismiss-before.web.app/

Click on the "Show Dialog" button.
Click anywhere inside the dialog that is not a form field.
Observe the dialog being dismissed.

After change
https://dialog-dimiss-after.web.app/

Click on the "Show Dialog" button.
Click anywhere inside the dialog that is not a form field.
Observe the dialog not dismissed.

Fixes: #149001
Engine work: #176974
github-merge-queue bot pushed a commit that referenced this pull request Nov 18, 2025
…get and apply to ModalRoute (#177570)" (#178744)

<!-- start_original_pr_link -->
Reverts: #177570
<!-- end_original_pr_link -->
<!-- start_initiating_author -->
Initiated by: chingjun
<!-- end_initiating_author -->
<!-- start_revert_reason -->
Reason for reverting: Broke internal tests.
<!-- end_revert_reason -->
<!-- start_original_pr_author -->
Original PR Author: flutter-zl
<!-- end_original_pr_author -->

<!-- start_reviewers -->
Reviewed By: {chunhtai}
<!-- end_reviewers -->

<!-- start_revert_body -->
This change reverts the following previous change:
Fix premature dialog dismissal on Flutter Web when semantics are enabled
by correctly propagating hitTestBehavior through the semantics pipeline
and declaring modal routes as opaque to pointer events.

Before change
https://dialog-dismiss-before.web.app/

Click on the "Show Dialog" button.
Click anywhere inside the dialog that is not a form field.
Observe the dialog being dismissed.

After change
https://dialog-dimiss-after.web.app/

Click on the "Show Dialog" button.
Click anywhere inside the dialog that is not a form field.
Observe the dialog not dismissed.

Fixes: #149001
Engine work: #176974
<!-- end_revert_body -->

Co-authored-by: auto-submit[bot] <[email protected]>
IvoneDjaja pushed a commit to IvoneDjaja/flutter that referenced this pull request Nov 22, 2025
…pply to ModalRoute (flutter#177570)

Fix premature dialog dismissal on Flutter Web when semantics are enabled
by correctly propagating hitTestBehavior through the semantics pipeline
and declaring modal routes as opaque to pointer events.

Before change
https://dialog-dismiss-before.web.app/

Click on the "Show Dialog" button.
Click anywhere inside the dialog that is not a form field.
Observe the dialog being dismissed.

After change
https://dialog-dimiss-after.web.app/

Click on the "Show Dialog" button.
Click anywhere inside the dialog that is not a form field.
Observe the dialog not dismissed.

Fixes: flutter#149001
Engine work: flutter#176974
IvoneDjaja pushed a commit to IvoneDjaja/flutter that referenced this pull request Nov 22, 2025
…get and apply to ModalRoute (flutter#177570)" (flutter#178744)

<!-- start_original_pr_link -->
Reverts: flutter#177570
<!-- end_original_pr_link -->
<!-- start_initiating_author -->
Initiated by: chingjun
<!-- end_initiating_author -->
<!-- start_revert_reason -->
Reason for reverting: Broke internal tests.
<!-- end_revert_reason -->
<!-- start_original_pr_author -->
Original PR Author: flutter-zl
<!-- end_original_pr_author -->

<!-- start_reviewers -->
Reviewed By: {chunhtai}
<!-- end_reviewers -->

<!-- start_revert_body -->
This change reverts the following previous change:
Fix premature dialog dismissal on Flutter Web when semantics are enabled
by correctly propagating hitTestBehavior through the semantics pipeline
and declaring modal routes as opaque to pointer events.

Before change
https://dialog-dismiss-before.web.app/

Click on the "Show Dialog" button.
Click anywhere inside the dialog that is not a form field.
Observe the dialog being dismissed.

After change
https://dialog-dimiss-after.web.app/

Click on the "Show Dialog" button.
Click anywhere inside the dialog that is not a form field.
Observe the dialog not dismissed.

Fixes: flutter#149001
Engine work: flutter#176974
<!-- end_revert_body -->

Co-authored-by: auto-submit[bot] <[email protected]>
mboetger pushed a commit to mboetger/flutter that referenced this pull request Dec 2, 2025
…pply to ModalRoute (flutter#177570)

Fix premature dialog dismissal on Flutter Web when semantics are enabled
by correctly propagating hitTestBehavior through the semantics pipeline
and declaring modal routes as opaque to pointer events.

Before change
https://dialog-dismiss-before.web.app/

Click on the "Show Dialog" button.
Click anywhere inside the dialog that is not a form field.
Observe the dialog being dismissed.

After change
https://dialog-dimiss-after.web.app/

Click on the "Show Dialog" button.
Click anywhere inside the dialog that is not a form field.
Observe the dialog not dismissed.

Fixes: flutter#149001
Engine work: flutter#176974
mboetger pushed a commit to mboetger/flutter that referenced this pull request Dec 2, 2025
…get and apply to ModalRoute (flutter#177570)" (flutter#178744)

<!-- start_original_pr_link -->
Reverts: flutter#177570
<!-- end_original_pr_link -->
<!-- start_initiating_author -->
Initiated by: chingjun
<!-- end_initiating_author -->
<!-- start_revert_reason -->
Reason for reverting: Broke internal tests.
<!-- end_revert_reason -->
<!-- start_original_pr_author -->
Original PR Author: flutter-zl
<!-- end_original_pr_author -->

<!-- start_reviewers -->
Reviewed By: {chunhtai}
<!-- end_reviewers -->

<!-- start_revert_body -->
This change reverts the following previous change:
Fix premature dialog dismissal on Flutter Web when semantics are enabled
by correctly propagating hitTestBehavior through the semantics pipeline
and declaring modal routes as opaque to pointer events.

Before change
https://dialog-dismiss-before.web.app/

Click on the "Show Dialog" button.
Click anywhere inside the dialog that is not a form field.
Observe the dialog being dismissed.

After change
https://dialog-dimiss-after.web.app/

Click on the "Show Dialog" button.
Click anywhere inside the dialog that is not a form field.
Observe the dialog not dismissed.

Fixes: flutter#149001
Engine work: flutter#176974
<!-- end_revert_body -->

Co-authored-by: auto-submit[bot] <[email protected]>
reidbaker pushed a commit to AbdeMohlbi/flutter that referenced this pull request Dec 10, 2025
…cs. (flutter#176974)

Implements engine-side declarative pointer event handling for semantics.

Framework-side to be implemented in next PR.

Fixes flutter#149001.

**Before change**
https://dialog-dismiss-before.web.app/

Click on the "Show Dialog" button.
Click anywhere inside the dialog that is not a form field.
Observe the dialog being dismissed. 

**After change**
https://dialog-dimiss-after.web.app/

Click on the "Show Dialog" button.
Click anywhere inside the dialog that is not a form field.
Observe the dialog not dismissed.
reidbaker pushed a commit to AbdeMohlbi/flutter that referenced this pull request Dec 10, 2025
…pply to ModalRoute (flutter#177570)

Fix premature dialog dismissal on Flutter Web when semantics are enabled
by correctly propagating hitTestBehavior through the semantics pipeline
and declaring modal routes as opaque to pointer events.

Before change
https://dialog-dismiss-before.web.app/

Click on the "Show Dialog" button.
Click anywhere inside the dialog that is not a form field.
Observe the dialog being dismissed.

After change
https://dialog-dimiss-after.web.app/

Click on the "Show Dialog" button.
Click anywhere inside the dialog that is not a form field.
Observe the dialog not dismissed.

Fixes: flutter#149001
Engine work: flutter#176974
reidbaker pushed a commit to AbdeMohlbi/flutter that referenced this pull request Dec 10, 2025
…get and apply to ModalRoute (flutter#177570)" (flutter#178744)

<!-- start_original_pr_link -->
Reverts: flutter#177570
<!-- end_original_pr_link -->
<!-- start_initiating_author -->
Initiated by: chingjun
<!-- end_initiating_author -->
<!-- start_revert_reason -->
Reason for reverting: Broke internal tests.
<!-- end_revert_reason -->
<!-- start_original_pr_author -->
Original PR Author: flutter-zl
<!-- end_original_pr_author -->

<!-- start_reviewers -->
Reviewed By: {chunhtai}
<!-- end_reviewers -->

<!-- start_revert_body -->
This change reverts the following previous change:
Fix premature dialog dismissal on Flutter Web when semantics are enabled
by correctly propagating hitTestBehavior through the semantics pipeline
and declaring modal routes as opaque to pointer events.

Before change
https://dialog-dismiss-before.web.app/

Click on the "Show Dialog" button.
Click anywhere inside the dialog that is not a form field.
Observe the dialog being dismissed.

After change
https://dialog-dimiss-after.web.app/

Click on the "Show Dialog" button.
Click anywhere inside the dialog that is not a form field.
Observe the dialog not dismissed.

Fixes: flutter#149001
Engine work: flutter#176974
<!-- end_revert_body -->

Co-authored-by: auto-submit[bot] <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

a: accessibility Accessibility, e.g. VoiceOver or TalkBack. (aka a11y) a: text input Entering text in a text field or keyboard related problems engine flutter/engine related. See also e: labels. framework flutter/packages/flutter repository. See also f: labels. platform-web Web applications specifically

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Flutter Web] dialogs dismissed prematurely with ensureSemantics

3 participants