-
Notifications
You must be signed in to change notification settings - Fork 3.5k
[url_launcher] fix: Link widget Tab traversal #9815
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[url_launcher] fix: Link widget Tab traversal #9815
Conversation
There was a problem hiding this 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 aims to fix a TAB traversal issue on the web for the Link widget by adding excludeSemantics: true
to the wrapping Semantics
widget. This prevents the child widget's semantics from conflicting and creating extra focusable DOM nodes. A new integration test is added to verify this behavior.
My review focuses on the new test case. I've found a bug where SemanticsHandle.dispose()
is called twice, and I've also questioned a skipped assertion that seems critical for verifying the fix. I've provided a code suggestion to address both points.
packages/url_launcher/url_launcher_web/example/integration_test/link_widget_test.dart
Outdated
Show resolved
Hide resolved
Thanks for tackling this issue! Unfortunately, @chunhtai do you have suggestions on how to make this work? Maybe making the child |
Isn't |
I don't think the original use case makes sense. If their end goal is to create a link that looks like a button, they should style it themselves instead of wrapping button with a link. The original issue is like doing <a href="https://www.w3schools.com"><button type="button" onclick="alert('Hello world!')">Click Me!</button></a> |
on I forgot it doesn't register ontap. yeah in this case, Link is not a full fledged The problem is elevated button itself will create a semantics container. You mentioned mergesemantics doesn't work, do you know which part it is not working? |
This is actually exactly the use case that the In the past, people did: SomeButton(
onPressed: () {
launchUrl("https://www.w3schools.com");
},
child: Text("Click here"),
) and complained that they didn't get a proper web link behavior (cmd+click, context menu, etc). So we wanted people to do this instead: Link(
uri: Uri.parse("https://www.w3schools.com"),
builder: (ctx, onPressed) => SomeButton(
onPressed: onPressed,
child: Text("Click here"),
),
) which lets them use all existing buttons and widgets, and makes them behave like real web links. |
If you do this on the web
you will also need two tabs |
Yes, the problem is that when you merge them, the semantics's Uri of the link gets lost. It looks like the engine is removing it. Likely because the child of the Link widget has its semantics button and is is taking precedence over the link's semantics properties. Interesting enough, the Link's semantics Will share the semantics tree diff here in a few hours |
I can think of several way.
|
@chunhtai any way you could help me with the fix in Flutter's framework/engine? Initially I though by adding the missing I would say, I'm now bakc to square zero as I ran out of ideas, would appreciate some hints on where to start |
Yeah, I totally missed this, let me try again. btw, I am mostly familiar with the framework & pretty new to the engine |
Ok, this is ready for review, I still would love the Link widget to merge the semantics itself, if you allow for it. Reason being without this, the framework/engine fix is somewhat useless and we would still need to educate customers in how to "workaround the issue". By letting |
Finally have a draft PR for the engine: flutter/flutter#174473. Pleas have a look! Turns out I was missing the commands #9815 (comment) to very my fixes 🫠 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, except for the change log and ci
@chunhtai any hints on why some tests are failing? 🤔 It is curious because:
Is it ok to merge with the unrelated failing tests? |
…'s (#174473) Fixes #157689 Flutter packages PR counterpart: - flutter/packages#9815 ## 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. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. **Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed.
This reverts commit 2d651b2.
No, absolutely not. If you believe there are unrelated failures, escalate to someone, don't just force-land your PR. If you are wrong, then you will break the tree, and if you are right, then you are effectively landing a PR into a broken tree for a purpose other than fixing the tree, which isn't allowed either. |
All presubmits are passing in the revert PR. |
flutter/packages@24588c6...2d651b2 2025-09-08 pedromassango.developer@gmail.com [url_launcher] fix: Link widget Tab traversal (flutter/packages#9815) 2025-09-08 engine-flutter-autoroll@skia.org Roll Flutter from 87d5b75 to 973320c (25 revisions) (flutter/packages#9977) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC flutter-ecosystem@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
Reverts #9815 The tree is now broken in exactly the way the presubmits for that PR were broken; it should not have landed.
Tries to fix the TAB traversal issue on web by ensuring the semantics of the
Link
are merged with its children. The buttons are treated as LINKS only and this prevents semantic conflicts that would create extra focusable DOM nodes.With
MergeSemantics
, the semantics tree was not generated properly, e.glinkUrl
value gets removed from the final semantics tree. This is being fixed in the engine, see flutter/flutter#174473Fixes flutter/flutter#157689
Required engine fix PR:
flutter/flutter#174473
Pre-Review Checklist
[shared_preferences]
pubspec.yaml
with an appropriate new version according to the [pub versioning philosophy], or I have commented below to indicate which [version change exemption] this PR falls under1.CHANGELOG.md
to add a description of the change, [following repository CHANGELOG style], or I have commented below to indicate which [CHANGELOG exemption] this PR falls under1.///
).If you need help, consider asking for advice on the #hackers-new channel on [Discord].
Note: The Flutter team is currently trialing the use of Gemini Code Assist for GitHub. Comments from the
gemini-code-assist
bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed.Footnotes
Regular contributors who have demonstrated familiarity with the repository guidelines only need to comment if the PR is not auto-exempted by repo tooling. ↩ ↩2 ↩3