Tabindex not working in Chrome (React app)
all: initial
resets all CSS properties of the node with initial properties.
For display
property, the initial value would be inline
.
So, setting all: initial
to the root div would set the display
property to inline. An inline
element does not have height or width, so these are 0x0.
This is also because the div
contains only fixed, absolutely positioned elements.
React Modal checks if elements are focusable by running a loop through all the elements inside the modal. However, for an element to be focusable, it has to visible. For each element, we have to iterate till the body element to ensure it's visibility.
Here is the function that checks whether the element is visible.
function hidden(el) { return ( (el.offsetWidth <= 0 && el.offsetHeight <= 0) || el.style.display === "none" );}
As you can see, our div would have no offsetHeight
or offsetWidth
and would be deemed as hidden. Therefore, the modal cannot not be focused.
I had the same issue and was not able to get other solutions working quicky, so I came up with brute force approach. Make a ref to the container element that holds the focusable elements that you wish to make tabbable.
const formRef = useRef(); <ReactModalTabbing containerRef={formRef}> <form ref={formRef} onSubmit={handleSubmit} > <input type="text" /> <input type="text" /> <input type="text" /> <input type="text" /> </form> </ReactModalTabbing>
And this is the component
import React, { useState, useEffect } from 'react';const ReactModalTabbing = ({ containerRef, children }) => { const [configuredTabIndexes, setConfiguredTabIndexes] = useState(false); const focusableElements = () => { // found this method body here. //https://zellwk.com/blog/keyboard-focusable-elements/ return [...containerRef?.current?.querySelectorAll( 'a, button, input, textarea, select, details, [tabindex]:not([tabindex="-1"]):not([type="hidden"]):not([disabled])' )]; } const isTabbable = (element) =>{ if(element.getAttribute('tabindex')){ return true; } return false; } const findElementByTabIndex = (tabIndex) => { return containerRef?.current?.querySelector(`[tabindex="${tabIndex}"]`); } const moveFocusToTabIndex = (tabIndex) => { findElementByTabIndex(tabIndex)?.focus(); } const handleKeyDownEvent = (event) => { if(!isTabbable(event.target)){ return; } const tabIndex = parseInt(event.target.getAttribute('tabindex')); if(event.shiftKey && event.key === 'Tab'){ moveFocusToTabIndex(tabIndex - 1); }else if(event.key === 'Tab'){ //should probably make sure there is no other modifier key pressed. moveFocusToTabIndex(tabIndex + 1); } } useEffect(() => { if(!configuredTabIndexes && containerRef.current){ setConfiguredTabIndexes(true); focusableElements().forEach((el, index) => el.setAttribute('tabindex', index + 1)); containerRef?.current?.addEventListener('keydown', handleKeyDownEvent); } }); return children;}export default ReactModalTabbing;