react-focus-lock icon indicating copy to clipboard operation
react-focus-lock copied to clipboard

Nested Portals Inside of a Focus Lock do not Receive Focus in IE 11

Open danlevy1 opened this issue 5 years ago • 2 comments
trafficstars

I am working on building a Menu component that opens up inside of a Modal component. This means that the Menu JSX is nested inside of the Modal JSX. The menu is a React Portal. When I tell the Menu to open from inside of the Modal, the Menu should receive focus (I programmatically call menu.focus()). In browsers other than IE 11, this works properly. In IE 11, however, the Menu does not receive focus (the focus stays in the Modal).

The Modal is wrapper in a ReactFocusLock component. The Menu is nested inside of the Modal which means that it is nested inside of the same ReactFocusLock component instance as Modal. The difference, however, is that Menu is a React Portal that renders outside of the Modal.

I have simplified example code below. The <input> and <button> represent the Modal and the inner button (named "exit portal") represents the Menu. In Chrome, for example, I can move between the "Enter Portal" and "Exit Portal" buttons by pressing the Enter/Return key. This is expected behavior. I can also tab between the input and "Enter Portal" button without focusing the "Exit Portal" button because the "Exit Portal" button renders outside of the ReactFocusLock component in the DOM. This is also expected behavior.

In IE 11, however, I must hit Enter twice to go from "Enter Portal" to "Exit Portal". To go back from "Exit Portal" to "Enter Portal", I only have to hit Enter once. Also, if the "Exit Portal" button is currently focused and I hit the Tab key, the <input> gets focused and then hitting Tab no longer works.

It appears that these problems are bugs in IE 11 and I have traced them down to ReactFocusLock. Please let me know if you need any more info. I really appreciate the time that you put into this library - it's a life saver!!

The example code below was bootstrapped with Create React App:

import "react-app-polyfill/ie11";
import React, { useRef } from "react";
import ReactDOM, { createPortal } from "react-dom";
import ReactFocusLock from "react-focus-lock";
import "./index.css";

const App = () => {
    const normalButtonRef = useRef();
    const portalButtonRef = useRef();

    return (
        <ReactFocusLock>
            <div>
                <input placeholder="Random imput to check for focus" size="30" />
                <button
                    ref={normalButtonRef}
                    onClick={() => portalButtonRef.current.focus()}
                >
                    Enter Portal
                </button>

                {createPortal(
                    <div>
                        <button
                            ref={portalButtonRef}
                            onClick={() => normalButtonRef.current.focus()}
                        >
                            Exit Portal
                        </button>
                    </div>,
                    document.body
                )}
            </div>
        </ReactFocusLock>
    );
};

ReactDOM.render(
    <React.StrictMode>
        <App />
    </React.StrictMode>,
    document.getElementById("root")
);

Here are my package.json dependencies:

"react": "^16.13.1",
"react-app-polyfill": "^1.0.6",
"react-dom": "^16.13.1",
"react-focus-lock": "^2.4.1",

danlevy1 avatar Sep 09 '20 21:09 danlevy1

If this is not working - then it is not working and I cannot fix it. However you probably may - using shards prop

<ReactFocusLock shards={[portalButtonRef]}>

That will explicitly tell FocusLock that it shall consider portalled button as a part of itself. You would be even better to provide ref to parent node of the button (top portalled node).

I hope this one line fix will resolve the for you.

theKashey avatar Sep 09 '20 23:09 theKashey

This is now an issue in all browsers in React 17. Is this a related issue: https://github.com/theKashey/react-focus-lock/issues/134

danlevy1 avatar Aug 18 '21 16:08 danlevy1

This issue has been marked as "stale" because there has been no activity for 2 months. If you have any new information or would like to continue the discussion, please feel free to do so. If this issue got buried among other tasks, maybe this message will reignite the conversation. Otherwise, this issue will be closed in 7 days. Thank you for your contributions so far.

stale[bot] avatar Apr 30 '23 12:04 stale[bot]