Skip to content

[Bug]: Keyborg malfunction inside microfrontends with no isolation #34465

@mathis-m

Description

@mathis-m

Component

Utilities

Package version

any

React version

any

Environment

-

Important

This issue affects D365 Model Driven Apps with PCFs deployed.

Real-world impact: This is a critical issue for Microsoft Dynamics 365, where PCFs (Power Apps Component Framework) come with FluentUI v9 bundled. For example, a standard PCF with FluentUI v9 Combobox component will not indicate keyboard navigation mode when users interact with the component using the keyboard, because the Keyborg instance created by the PCF is overridden by the one created by the out-of-the-box script.

Current Behavior

Expected Behavior

keyborg instances are not overriding themself

Ref. Issue: microsoft/keyborg#99

Reproduction

https://stackblitz.com/edit/ht9elwz1

Steps to reproduce

  1. See repro or comment

Are you reporting an Accessibility issue?

yes

Suggested severity

Urgent - No workaround and Products/sites are affected

Products/sites affected

No response

Are you willing to submit a PR to fix?

yes

Validations

  • Check that there isn't already an issue that reports the same bug to avoid creating a duplicate.
  • The provided reproduction is a minimal reproducible example of the bug.

npm-patch (keyborg+2.6.0.patch)

diff --git a/node_modules/keyborg/dist/esm/index.js b/node_modules/keyborg/dist/esm/index.js
index 0b18026..2d18f5d 100644
--- a/node_modules/keyborg/dist/esm/index.js
+++ b/node_modules/keyborg/dist/esm/index.js
@@ -216,7 +216,6 @@ function getLastFocusedProgrammatically(win) {
 
 // src/Keyborg.ts
 var _dismissTimeout = 500;
-var _lastId = 0;
 var KeyborgCore = class {
   constructor(win, props) {
     this._isNavigatingWithKeyboard_DO_NOT_USE = false;
@@ -266,7 +265,13 @@ var KeyborgCore = class {
         }
       }
     };
-    this.id = "c" + ++_lastId;
+    if (win?.__keyborg?.lastId !== undefined) {
+      this.id = "c" + ++win.__keyborg.lastId;
+    } else {
+      win.__keyborg = win.__keyborg || {};
+      win.__keyborg.lastId = 10001;
+      this.id = "c10001";
+    }
     this._win = win;
     const doc = win.document;
     if (props) {
@@ -374,15 +379,19 @@ var KeyborgCore = class {
 var Keyborg = class _Keyborg {
   constructor(win, props) {
     this._cb = [];
-    this._id = "k" + ++_lastId;
     this._win = win;
     const current = win.__keyborg;
     if (current) {
+      current.lastId = current.lastId || 10000;
+      this._id = "k" + ++current.lastId;
       this._core = current.core;
       current.refs[this._id] = this;
     } else {
       this._core = new KeyborgCore(win, props);
+      let lastId = win.__keyborg?.lastId || 10000;
+      this._id = "k" + ++lastId;
       win.__keyborg = {
+        lastId: lastId,
         core: this._core,
         refs: { [this._id]: this }
       };
diff --git a/node_modules/keyborg/dist/index.js b/node_modules/keyborg/dist/index.js
index eb4bbe2..939a490 100644
--- a/node_modules/keyborg/dist/index.js
+++ b/node_modules/keyborg/dist/index.js
@@ -247,7 +247,6 @@ function getLastFocusedProgrammatically(win) {
 
 // src/Keyborg.ts
 var _dismissTimeout = 500;
-var _lastId = 0;
 var KeyborgCore = class {
   constructor(win, props) {
     this._isNavigatingWithKeyboard_DO_NOT_USE = false;
@@ -297,7 +296,13 @@ var KeyborgCore = class {
         }
       }
     };
-    this.id = "c" + ++_lastId;
+    if (win?.__keyborg?.lastId !== undefined) {
+      this.id = "c" + ++win.__keyborg.lastId;
+    } else {
+      win.__keyborg = win.__keyborg || {};
+      win.__keyborg.lastId = 10001;
+      this.id = "c10001";
+    }
     this._win = win;
     const doc = win.document;
     if (props) {
@@ -405,15 +410,19 @@ var KeyborgCore = class {
 var Keyborg = class _Keyborg {
   constructor(win, props) {
     this._cb = [];
-    this._id = "k" + ++_lastId;
     this._win = win;
     const current = win.__keyborg;
     if (current) {
+      current.lastId = current.lastId || 10000;
+      this._id = "k" + ++current.lastId;
       this._core = current.core;
       current.refs[this._id] = this;
     } else {
       this._core = new KeyborgCore(win, props);
+      let lastId = win.__keyborg?.lastId || 10000;
+      this._id = "k" + ++lastId;
       win.__keyborg = {
+        lastId: lastId,
         core: this._core,
         refs: { [this._id]: this }
       };

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions