最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - React - Prevent focus going out of modal when tabbing - Stack Overflow

programmeradmin3浏览0评论

I have built a react modal on my own. When I press tab key while the modal is opened, the focus still goes to the background page. How to restrict the focus within the ponents inside the modal?

What should be the logic below?

onKeyPress (e) {
   if (e.keyCode === 9) {
       e.preventDefault();
      // logic here?
   }
}

React Modal code:

<ReactModal onKeyPress={this.onKeyPress} >
   <input type="text"/>
   <input type="text"/>
</ReactModal>

I have built a react modal on my own. When I press tab key while the modal is opened, the focus still goes to the background page. How to restrict the focus within the ponents inside the modal?

What should be the logic below?

onKeyPress (e) {
   if (e.keyCode === 9) {
       e.preventDefault();
      // logic here?
   }
}

React Modal code:

<ReactModal onKeyPress={this.onKeyPress} >
   <input type="text"/>
   <input type="text"/>
</ReactModal>
Share Improve this question edited Jul 17, 2017 at 13:48 piet.t 11.9k21 gold badges44 silver badges55 bronze badges asked Jul 4, 2017 at 9:08 Jefree SujitJefree Sujit 1,5865 gold badges22 silver badges38 bronze badges
Add a ment  | 

3 Answers 3

Reset to default 6

Well, you can do it using a focus trap. Check out this npm module for that. Merely wrap your which contains modal with a focus-trap like this.

    <FocusTrap
              focusTrapOptions={{
                ...
              }}
            >
              <div className="trap">
                <p>
                  Here is a focus trap
                  {' '}
                  <a href="#">with</a>
                  {' '}
                  <a href="#">some</a>
                  {' '}
                  <a href="#">focusable</a>
                  {' '}
                  parts.
                </p>
                <p>
                  <button onClick={this.someCallback}>
                    Click Me
                  </button>
                </p>
              </div>

</FocusTrap>

Instead of giving you advice on implementing this, I suggest that you just don’t implement it yourself. It is hard to get right considering accessibility.

Instead, I would suggest you to use an accessible off-the-shelf modal ponent such as react-modal. It is pletely customizable, you can put anything you want inside of it, but it handles accessibility correctly so that blind people can still use your modal.

I found a very simple vanillaJS solution that should work in any modern browser. And can be easily adapted to any React ponent. It doesn't require any additional modules or plicated logic, watching keys or whatnot.

const container=document.querySelector("_selector_for_the_container_")

//optional: needed only if the container element is not focusable already
container.setAttribute("tabindex","0")

container.addEventListener("focusout", (ev)=>{
  if (!container.contains(ev.relatedTarget)) container.focus()
})

The mode of operation is very simple:

  • makes the container focusable, if not already
  • adds an event listener to the focusout event which fires when the focus is about to go outside of the container
  • Checks if the next target of the focus is in fact outside of the container, and if so, then puts the focus back to the container itself

The last check is needed because the focusout event also fires when the focus moves from one element to the another within the container.

Note: the focus can leave the page, eg the address bar of the browser. This doesn't seem to be preventable - at least according to my testing in Chrome.

I had to lock focus within a modal that we had used within a React ponent. I added eventListner for KEY DOWN and collected Tab and Shift+Tab

class Modal extends Component {
    ponentDidMount() {
        window.addEventListener("keyup", this.handleKeyUp, false);
        window.addEventListener("keydown", this.handleKeyDown, false);
    }

    ponentWillUnmount() {
        window.removeEventListener("keyup", this.handleKeyUp, false);
        window.removeEventListener("keydown", this.handleKeyDown, false);
    }

    handleKeyDown = (e) => {

        //Fetch node list from which required elements could be grabbed as needed.
        const modal = document.getElementById("modal_parent");
        const tags = [...modal.querySelectorAll('select, input, textarea, button, a, li')].filter(e1 => window.getComputedStyle(e1).getPropertyValue('display') === 'block');
        const focusable = modal.querySelectorAll('button, [href], input, select, textarea, li, a,[tabindex]:not([tabindex="-1"])');
        const firstFocusable = focusable[0];
        const lastFocusable = focusable[focusable.length - 1];

        if (e.ctrlKey || e.altKey) {
            return;
        }

        const keys = {
            9: () => { //9 = TAB
                if (e.shiftKey && e.target === firstFocusable) {
                    lastFocusable.focus();
                }

                if (e.target === lastFocusable) {
                    firstFocusable.focus();
                }
            }
        };

        if (keys[e.keyCode]) {
            keys[e.keyCode]();
        }
    }
}
发布评论

评论列表(0)

  1. 暂无评论