简体   繁体   English

Tabindex 在 Chrome 中不起作用(React 应用程序)

[英]Tabindex not working in Chrome (React app)

I use react and react-modal to create an overlay over a website.我使用 react 和 react-modal 在网站上创建叠加层。 This overlay contains various elements and also a form (overview below).这个覆盖层包含各种元素和一个表单(下面的概述)。 I want to be able to guide the user through the form using TAB keys.我希望能够使用 TAB 键引导用户完成表单。 I assigned tabindex=0 to the required elements to be tabbable in order of appearance.我将tabindex=0分配给所需的元素,以便按出现顺序进行 tabbable。

My problem is: It does not work in Chrome (Version 61.0.3163.100) while it does work in Firefox.我的问题是:它在 Chrome(版本 61.0.3163.100)中不起作用,而在 Firefox 中起作用。 I read that this happens if any element up the DOM-tree is invisible or has height/width of 0. I made some styling changes to fix that but with no effect.我读到如果 DOM 树上的任何元素不可见或高度/宽度为 0,就会发生这种情况。我做了一些样式更改来解决这个问题,但没有任何效果。

<div class="ReactModalPortal">
<div data-reactroot="" class="ReactModal__Overlay" style="position: fixed; top: 0px; left: 0px; right: 0px; bottom: 0px;">
    <div class="ReactModal__Content" tabindex="-1" aria-label="Questionnaire" style="position: absolute; top: 0px; left: 0px; right: 0px; height: 100%; background: transparent none repeat scroll 0% 0%; overflow: auto;">
        <!-- Some other stuff and nested elements -->
        <div id="...">
            <form>
                <input tabindex="0">
                <button tabindex="0">
            </form> 
        </div>   
    </div>   
</div>    

As you can see one of the parent elements has tabindex="-1" .如您所见,其中一个父元素具有tabindex="-1" When changing it through the inspect function in Chrome or programmatically with JS the problem still persists (or is it a difference if the element was rendered with this index initially?).当通过 Chrome 中的检查功能或使用 JS 以编程方式更改它时,问题仍然存在(或者如果元素最初使用此索引呈现,是否有所不同?)。

Update更新

I realized that something else was causing the issues.我意识到是其他原因导致了这些问题。 I was using the CSS attribute initial: all on the root node of my modal to fence my inner CSS from everything outside.我在我的模态的根节点上使用了 CSS 属性initial: all来将我的内部 CSS 与外部的所有内容隔离开来。 For some reason this was preventing the tabindex from working.出于某种原因,这阻止了 tabindex 工作。 If you can help me understanding I will reward this wis the bounty.如果你能帮助我理解,我会奖励这个赏金。 My workaround is just not using all: initial (it is not IE-compatible anyways but also there is no real good alternative I am aware of).我的解决方法只是不使用all: initial (无论如何它与 IE 不兼容,但我知道也没有真正好的替代方案)。

all: initial resets all CSS properties of the node with initial properties. all: initial使用初始属性重置节点的所有 CSS 属性。

For display property, the initial value would be inline .对于display属性,初始值将是inline

So, setting all: initial to the root div would set the display property to inline.因此,将all: initial设置为根 div 会将display属性设置为内联。 An inline element does not have height or width, so these are 0x0. inline元素没有高度或宽度,因此它们是 0x0。

This is also because the div contains only fixed, absolutely positioned elements.这也是因为div只包含固定的、绝对定位的元素。

React Modal checks if elements are focusable by running a loop through all the elements inside the modal. React 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.对于每个元素,我们必须迭代直到 body 元素以确保它的可见性。

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.如您所见,我们的 div 没有offsetHeightoffsetWidth ,将被视为隐藏。 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;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM