Cannot tab into cell contents

This issue has been tracked since 2022-09-19.

Describe the bug

RDG captures Tab key presses and manually implements navigation, suppressing the default browser behavior. This is problematic because cell contents such as links or buttons are not accessible by keyboard.

To Reproduce

  1. Render a link in column formatter
  2. Notice that you cannot access the link in the grid via keyboard

Link to code example: https://codesandbox.io/s/purple-glade-ipvy62

Expected behavior

Tabbing should use the browser behavior as much as possible so that cell contents can be tabbed into normally

Environment

  • react-data-grid version: 7.0.0-beta.18
  • react/react-dom version: 18.2.0

Additional context

amanmahajan7 wrote this answer on 2022-09-23

This is by design so the grid can control cell navigation but it allows custom formatters to define focus behavior. Here is the updated example
https://codesandbox.io/s/runtime-water-noucsp?file=/src/App.js

function LinkFormatter({ isCellSelected, row }) {
  const { ref, tabIndex } = useFocusRef(isCellSelected);
  return (
    <a ref={ref} tabIndex={tabIndex} href={row.href}>
      {row.name}
    </a>
  );
}
kycutler wrote this answer on 2022-09-23

@amanmahajan7 thanks for the example! I didn't know about the useFocusRef hook.

I was able to get something working -- It's a bit more complicated than the example I posted since we actually have a complex component inside the cell, so there are multiple focusable elements, and we can't modify everything since it's from a library.

My workaround was to use the useFocusRef hook as in your example and then add an onKeyDown listener to selectively prevent tab events from bubbling up to RDG:

if (ev.key === "Tab" && ref.current) {
  const focusableElements = ref.current.querySelectorAll(
    'a:not([disabled]), area:not([disabled]), button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex="0"]:not([disabled])'
  );
  const focusedElement = document.activeElement;

  // If we are focused on the root and will tab out, let the event bubble up.
  if (focusedElement === ref.current && (ev.shiftKey || focusableElements.length === 0)) {
    return;
  }

  // If we are tabbing forwards and are at the last focusable child, let the event bubble up.
  if (
    focusableElements.length > 0 &&
    focusedElement === focusableElements[focusableElements.length - 1] &&
    !ev.shiftKey
  ) {
    return;
  }

  // Otherwise, prevent the event from bubbling to RDG so that the browser tabbing behavior is applied.
  ev.stopPropagation();
}

It's not perfect (for example, tabbing backwards into a cell then requires you to tab forwards into the contents), but it will do for now.

If you have any other ideas for how to improve this, I would love to hear them. Otherwise I think this issue can be closed!

amanmahajan7 wrote this answer on 2022-12-23

This is the best solution as RDG cannot handle all the cases. Closing it for now .

More Details About Repo
Owner Name adazzle
Repo Name react-data-grid
Full Name adazzle/react-data-grid
Language TypeScript
Created Date 2015-03-06
Updated Date 2023-03-23
Star Count 5922
Watcher Count 129
Fork Count 2072
Issue Count 161

YOU MAY BE INTERESTED

Issue Title Created Date Updated Date