Make table scroll with selected table row with onKeyDown (React)

Viewed 40

I'm having some major difficulties trying to make my table scroll when going through the table rows with onKeyDown. What seems to be happening is that the event doesn't actually change when using the keyboard, even though selected is highlighting the selected row properly. If a table row in the middle of the table is clicked, the table will scroll only the first time the keyboard up or down is pressed. (which makes sense since its a new event).

I've tried wrapping the function handleKeyDown in useCallback in case it lost a reference between renders, but it didn't matter.

Does anyone have any suggestions on how I can get a new event on key press?

I'm leaving the main functions here to have a look at, however you can find a working Sandbox with the problem here: https://codesandbox.io/s/basictable-demo-material-ui-forked-54frpm?file=/demo.tsx

const handleKeyDown = (event) => {
    event.preventDefault();
    console.log(event.target);
    scrollIntoView(event.target);

    if (event.key === "ArrowUp") {
      if (selected === rows[0].id) return;
      setSelected(getNextRow(rows, selected, "up"));
    }

    if (event.key === "ArrowDown") {
      if (selected === rows[rows.length - 1].id) return;
      setSelected(getNextRow(rows, selected, "down"));
    }
  };
<TableRow
    key={row.id}
    sx={{ "&:last-child td, &:last-child th": { border: 0 } }}
    selected={isRowSelected(row.id)}
    onClick={() => handleSetSelected(row.id)}
    onKeyDown={handleKeyDown}
    tabIndex={0}
  const isRowSelected = (rowId) => {
    return rowId === selected;
  };

  const scrollIntoView = (element) => {
    if (element) {
      element.scrollIntoView({ behavior: "smooth", block: "center" });
    }
  };
const getNextRow = (rows, selected, direction) => {
  const index = rows.findIndex((row) => row.id === selected);
  if (direction === "up") return rows[index - 1].id;
  if (direction === "down") return rows[index + 1].id;
}

The events are logged into the console. If you click the first row, press the down arrow on your keyboard 2-3 times, you can inspect the logged elements and confirm they are all from the row that was actually clicked on, and not the ones selected with the keyboard.

Thanks for your help in advance.

Stephan Bakkelund Valois

1 Answers

I found a working solution that doesn't depend on the keyDown event itself.

As we're already calculating the next row with the function getNextRow that returns the id of our next row, we can utilize this to make it scroll.

First, we need to add the id our table row component:

<TableRow
    ....
    id={row.id}
> 

We can send the id we got from getNextRow to the scrollIntoView function, and fetch the html element with a querySelector, and that way scroll to the correct row:

const scrollIntoView = (id: string) => {
    const el = document.querySelector(`#${id}`)
    if (el) el.scrollIntoView({ behavior: 'smooth', block: 'center' })
}
Related