Search code examples
javascripthtmlreactjsfocusaccessibility

How to make a div and all its descendants unfocusable


I was trying to make a div and all its descendants unfocusable. I used a tabIndex -1 on the root div. But that was making focus move to its first focusable child. (The default behavior) Is there a workaround for this issue?

Example code

const SomeFunctionComponent = () => {
  // ... some logic ...

  const someTrustedHtml = `<p>Hello <a href="stackoverflow.com">World!</a></p>`;
  const content = React.createElement("div", {
    className: "some class name",
    dangerouslySetInnerHTML: {
      __html: someTrustedHtml;
    },
    tabIndex: -1, /* "tabindex": -1 does not work */
    // None of these options helped either
    // "data-is-focusable": false,
    // "aria-hidden": true,
    // disabled: true,
    // role: "presentation"
  });

  // ... more logic ...
  
  return (
    <div>
      {content}
      <button onClick={() => console.log("hello world")}></button>
      {/* some tab focusable elements */}
    </div>
  );
}

expected behavior: When SomeFunctionComponent gets focus, focus would move to the button

actual behavior: focus goes to the link in the dangerouslySetInnerHtml


Solution

  • tabindex is not inheritable. You have to set it on every element that is natively focusable.

    Interestingly enough, the spec says that setting it to -1 does not cause an element to be non-focusable, but I use that all the time and it works on all browsers.

    Note that the tabindex attribute cannot be used to make an element non-focusable. The only way a page author can do that is by disabling the element, or making it inert.