@massds/mayflower-react
Version:
React versions of Mayflower design system UI components
63 lines (50 loc) • 2.75 kB
JavaScript
/**
* focusTrapping: Trap keyboard focus inside of a modal
* @param {string} focusableSelectors(requied): css selectors for all the focusable elements inside of the modal
* @param {string} modalSelector(requied): css selector for the modal container
* @param {string} closeButtonSelector(optional): If the modal close button is outside of the modal container, add the css selector for it to be included as the first focusable element
* @param {event} keyEvent(requied): keydown event
*/
// check if an element is visibly displayed using computed style
const isDisplayed = el => {
const style = window.getComputedStyle(el);
return style.display !== 'none' && style.visibility !== 'hidden';
}; // filter out elements from array which are not visibly displayed
const filterDisplayedElements = elements => elements.length > 0 && elements.filter(el => isDisplayed(el));
export default ((_ref) => {
let _ref$focusableSelecto = _ref.focusableSelectors,
focusableSelectors = _ref$focusableSelecto === void 0 ? 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])' : _ref$focusableSelecto,
closeButtonSelector = _ref.closeButtonSelector,
modalSelector = _ref.modalSelector,
keyEvent = _ref.keyEvent;
// add all the elements inside modal which you want to make focusable
const focusableElements = focusableSelectors;
const modal = document.querySelector(modalSelector); // select the modal by it's id
const e = keyEvent;
if (modal) {
const focusableNodeArray = Array.from(modal.querySelectorAll(focusableElements));
let focusableContent = modal && filterDisplayedElements(focusableNodeArray);
if (closeButtonSelector) {
const closeButton = document.querySelector(closeButtonSelector);
focusableContent = [closeButton].concat(focusableContent);
}
const firstFocusableElement = focusableContent[0]; // get first element to be focused inside modal
const lastFocusableElement = focusableContent[focusableContent.length - 1]; // get last element to be focused inside modal
const isTabPressed = e.key === 'Tab';
if (!isTabPressed) {
return;
}
if (e.shiftKey) {
// if shift key pressed for shift + tab combination
if (document.activeElement === firstFocusableElement) {
lastFocusableElement.focus(); // add focus for the last focusable element
e.preventDefault();
}
} else if (document.activeElement === lastFocusableElement) {
// if tab key is pressed
// if focused has reached to last focusable element then focus first focusable element after pressing tab
firstFocusableElement.focus(); // add focus for the first focusable element
e.preventDefault();
}
}
});