Vanilla javascript Trap Focus in modal (accessibility tabbing )

[亡魂溺海] 提交于 2021-02-10 12:36:19

问题


This should be pretty simple but for some reason it isn't working, I'm getting the proper console.logs at the right time, but the focus isn't going to the correct place, please refer to my jsfiddle

https://jsfiddle.net/bqt0np9d/

function checkTabPress(e) {
    "use strict";
    // pick passed event of global event object
    e = e || event;

    if (e.keyCode === 9) {
        if (e.shiftKey) {
            console.log('back tab pressed');
            firstItem.onblur=function(){
                console.log('last a focus left');
                lastItem.focus();
            };
            e.preventDefault();
        }
        console.log('tab pressed');
        lastItem.onblur=function(){
            console.log('last a focus left');
            firstItem.focus();
        };
        e.preventDefault();
    }
}
modal.addEventListener('keyup', checkTabPress);

回答1:


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

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

    componentWillUnmount() {
        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]();
        }
    }
}



回答2:


One of the problems is that you are using keyup instead of keydown. The keyup will only fire after the tab has already fired. However, making that change to your code results in the keyboard being trapped on one of the links. The code is flawed.

Here is some code that does what you want (using jQuery)

http://dylanb.github.io/javascripts/periodic-1.1.js

// Add keyboard handling for TAB circling

  $modal.on('keydown', function (e) {
    var cancel = false;
    if (e.ctrlKey || e.metaKey || e.altKey) {
      return;
    }
    switch(e.which) {
      case 27: // ESC
        $modal.hide();
        lastfocus.focus();
        cancel = true;
        break;
      case 9: // TAB
        if (e.shiftKey) {
          if (e.target === links[0]) {
            links[links.length - 1].focus();
            cancel = true;
          }
        } else {
          if (e.target === links[links.length - 1]) {
            links[0].focus();
            cancel = true;
          }
        }
        break;
    }
    if (cancel) {
      e.preventDefault();
    }
  });

You can see a working version of this dialog here

http://dylanb.github.io/periodic-aria11-attributes.html

Click the text in one of the colored boxes to see the dialog pop up.




回答3:


The e.preventDefault() has no effect on the keyup event (as the default browser action has already been fired)

Despite this, your example works. But only if there are links before and after the modal

If you change your HTML code with the following, adding one link before and one link after the modal; you will see that your focus is trapped in the modal:

 <a href="#">other link</a>
 <div id="modal">
     <a href="#">Link One</a>
     <a href="#">Link Two</a>
 </div>
 <a href="#">other link</a>

That's because there is no default browser action in such case, and then no action to prevent.




回答4:


Trapping focus within a modal is very hard to do it on your own. If you're able to install third-party dependencies in your project, you can use the focus-trap package.

You can easily trap focus to any component with vanilla Javascript;

import { createFocusTrap } from 'focus-trap'

const modal = document.getElementById('modal')

const focusTrap = createFocusTrap('#modal', {
    onActivate: function () {
        modal.className = 'trap is-visible'
    },
    onDeactivate: function () {
        modal.className = 'trap'
    },
})

document.getElementById('show').addEventListener('click', function () {
    focusTrap.activate()
})

document.getElementById('hide').addEventListener('click', function () {
    focusTrap.deactivate()
})

or even React;

import React from 'react'
import ReactDOM from 'react-dom'
// Use the wrapper package of `focus-trap` to use with React.
import FocusTrap from 'focus-trap-react'

const Demo = () => {
    const [showModal, setShowModal] = React.useState(false)

    return (
        <div>
            <button onClick={() => setShowModal(true)}>show modal</button>

            <FocusTrap active={showModal}>
                <div id="modal">
                    Modal with <a href="#">with</a> <a href="#">some</a>{' '}
                    <a href="#">focusable</a> elements.
                    <button onClick={() => setShowModal(false)}>
                        hide modal
                    </button>
                </div>
            </FocusTrap>
        </div>
    )
}

ReactDOM.render(<Demo />, document.getElementById('demo'))

I did a small write-up about the package here, which explains how to use it with either vanilla Javascript or React.



来源:https://stackoverflow.com/questions/32996817/vanilla-javascript-trap-focus-in-modal-accessibility-tabbing

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!