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() {