question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Autofocus keeps firing inside shadow dom

See original GitHub issue

A problem occurs when a focus lock component with autoFocus is rendered inside a shadow root. Component successfully focuses first interactive element, but then repeatedly resets focus to it, when a user tries to focus anything else.

Here is the code of the demo reproducing the issue:

import "./styles.css";
import { StrictMode } from "react";
import ReactDOM from "react-dom";
import ReactFocusLock from "react-focus-lock";

export default function App() {
  return (
    <ReactFocusLock autoFocus={true}>
      <div className="App">
        <h1>Hello CodeSandbox</h1>
        <input></input>
        <input></input>
        <h2>Start editing to see some magic happen!</h2>
      </div>
    </ReactFocusLock>
  );
}
const template = document.createElement("template");
template.innerHTML = `

<div>
  <p part="title">React attached below</p>
  <div id="root"></div>
</div>
`;

export class WebComp extends HTMLElement {
  constructor() {
    super();
    // attach to the Shadow DOM
    const root = this.attachShadow({ mode: "closed" });
    root.appendChild(template.content.cloneNode(true));
    ReactDOM.render(
      <StrictMode>
        <App />
      </StrictMode>,
      root
    );
  }
}

window.customElements.define("web-comp", WebComp);

Issue Analytics

  • State:open
  • Created 2 years ago
  • Reactions:4
  • Comments:7 (4 by maintainers)

github_iconTop GitHub Comments

2reactions
Jaodicommented, Jan 19, 2022

Here is a test that reliably fails on the current version. If you remove the use of FocusLock component, the test passes.

I had to update the version of jsdom this project is using, because currently installed version of the library does not support shadow DOM yet

diff --git a/_tests/FocusLock.spec.js b/_tests/FocusLock.spec.js
index 0b07d7e..19f8928 100644
--- a/_tests/FocusLock.spec.js
+++ b/_tests/FocusLock.spec.js
@@ -905,6 +905,54 @@ text
       });
     });
 
+    describe('child creates a shadow tree', () => {
+      it('does not stop focus from moving inside the shadow DOM', () => {
+        function App() {
+          return (
+            <FocusLock>
+              <div className="App">
+                <h1>Hello CodeSandbox</h1>
+                <input id="first-input" />
+                <input id="second-input" />
+                <h2>Start editing to see some magic happen!</h2>
+              </div>
+            </FocusLock>
+          );
+        }
+        const template = document.createElement('template');
+        template.innerHTML = `
+          <div>
+            <p part="title">React attached below</p>
+            <div id="root"></div>
+          </div>
+        `;
+        class WebComp extends HTMLElement {
+          constructor() {
+            super();
+            // attach to the Shadow DOM
+            const root = this.attachShadow({ mode: 'closed' });
+            root.appendChild(template.content.cloneNode(true));
+            this.ref = {
+              focused: () => root.activeElement,
+              focusSecond: () => root.querySelector('#second-input').focus(),
+            };
+            ReactDOM.render(
+              <App />,
+              root,
+            );
+          }
+        }
+        window.customElements.define('web-comp', WebComp);
+        const webComp = document.createElement('web-comp');
+        document.body.appendChild(webComp);
+
+        webComp.focus();
+        const { focused, focusSecond } = webComp.ref;
+        focusSecond();
+        expect(focused().id).to.be.equal('second-input');
+      });
+    });
+
     describe('groups', () => {
       it('false test', (done) => {
         const wrapper = mount(<div>
diff --git a/package.json b/package.json
index c4adba0..d85297e 100644
--- a/package.json
+++ b/package.json
@@ -79,7 +79,7 @@
     "eslint-plugin-jsx-a11y": "^6.2.1",
     "eslint-plugin-mocha": "^5.3.0",
     "eslint-plugin-react": "^7.13.0",
-    "jsdom": "15.1.1",
+    "jsdom": "^19.0.0",
     "jsdom-global": "^3.0.2",
     "material-ui": "^0.20.0",
     "mocha": "^8.3.2",

1reaction
theKasheycommented, Feb 14, 2022

The test provided by @Jaodi has been added as a base specification for shadow-dom and react-focus-lock is currently passing it with the updated focus-lock functionality provided by @Shermayster

Necessary updates were released as a part of v 2.8.1

I cannot verify the correctness of this implementation as I don’t have a real usecase. Please try how the new version matching your expectations.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Managing focus in the shadow DOM | Read the Tea Leaves
The first issue is irksome but not impossible to solve: you just have to listen for dialog open/close events and keep track of...
Read more >
Shadow DOM v1 - Self-Contained Web Components
Handling focus #. If you recall from shadow DOM's event model, events that are fired inside shadow DOM are adjusted to look like...
Read more >
Focus inside Shadow DOM - Medium
In this demo, the first two input elements are part of a shadow root, but the last one is not — it's a...
Read more >
Shadow DOM - W3C
Shadow DOM specification is being upstreamed to DOM Standard [ WHATWG-DOM ], HTML Standard [ HTML ], CSS Scoping Module Level 1 ...
Read more >
Focus an element within a ShadowDOM - Stack Overflow
The problem arises when the window load event is triggered. Focus returns to the main body (verified by issuing document.activeElement in the ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found