wrap focus() in a post update callback (#38958)
diff --git a/lib/web_ui/lib/src/engine/semantics/tappable.dart b/lib/web_ui/lib/src/engine/semantics/tappable.dart index 2c8ad8a..311b5b7 100644 --- a/lib/web_ui/lib/src/engine/semantics/tappable.dart +++ b/lib/web_ui/lib/src/engine/semantics/tappable.dart
@@ -61,7 +61,9 @@ // Request focus so that the AT shifts a11y focus to this node. if (semanticsObject.isFlagsDirty && semanticsObject.hasFocus) { - element.focus(); + semanticsObject.owner.addOneTimePostUpdateCallback(() { + element.focus(); + }); } }
diff --git a/lib/web_ui/test/engine/semantics/semantics_test.dart b/lib/web_ui/test/engine/semantics/semantics_test.dart index 3de8054..e35d5f6 100644 --- a/lib/web_ui/test/engine/semantics/semantics_test.dart +++ b/lib/web_ui/test/engine/semantics/semantics_test.dart
@@ -1628,6 +1628,27 @@ semantics().semanticsEnabled = false; }); + + test('focuses on tappable after element has been attached', () async { + semantics() + ..debugOverrideTimestampFunction(() => _testTime) + ..semanticsEnabled = true; + + final SemanticsTester tester = SemanticsTester(semantics()); + tester.updateNode( + id: 0, + hasTap: true, + hasEnabledState: true, + isEnabled: true, + isButton: true, + isFocused: true, + rect: const ui.Rect.fromLTRB(0, 0, 100, 50), + ); + tester.apply(); + + expect(flutterViewEmbedder.glassPaneShadow!.activeElement, tester.getSemanticsObject(0).element); + semantics().semanticsEnabled = false; + }); } void _testImage() {