Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scroll with keyboard's up/down arrows keys in React?

I have a custom listbox, a div that contains a vertical list of other div children. I want to add an up/down arrows keys navigation to change which child is currently selected.

So when I click the first item and press the down arrow key, it should allow me to select the second item (following item). And if I click the up arrow key, it should select back the first item (previous item).

const renderInboxSummary = targetDetailsData.map((todo, index) => {
  const hasNewMessageInd = todo.hasNewMessageInd;
  return (
   <div onClick={() => this.handleClick(targetDetailsData, todo.aprReference, index)}>
      <div>
        {todo.aprRecordUserName}
      </div>
      <div>
        {todo.aprBranchCode}
      </div>
      <div>
        {todo.aprScreeName}
      </div>
  </div>
  );
});

Every div has a click event handler this.handleClick(targetDetailsData, todo.aprReference, index).

Enter image description here

like image 593
skarakas Avatar asked Dec 26 '18 11:12

skarakas


1 Answers

This can be done by using a ref in ReactJS and then adding an event listener for the keydown event and then moving the focus to the next or previous sibling.

Notes

  • I add tabindex attribute to each div to allow them to be focused upon
  • I use a ref on the wrapping element to listen for keydown
  • I check keycode for up/down to move to next/previous sibling
  • I believe the keycode for up/down on a full size keyboard is different, but I don't have one to test.

Solution

To test the demo, click on any div and then use up/down arrows

const { Component } = React;

class App extends Component {
  constructor(props) {
    super(props);
    this.myRef = React.createRef();
  }
  componentDidMount() {
    this.moveFocus();
  }
  moveFocus() {
    const node = this.myRef.current;
    node.addEventListener('keydown', function(e) {
      const active = document.activeElement;
      if(e.keyCode === 40 && active.nextSibling) {
        active.nextSibling.focus();
      }
      if(e.keyCode === 38 && active.previousSibling) {
        active.previousSibling.focus();
      }
    });
  }
  render() {
    return (
      <div ref={this.myRef}>
        <div tabindex="0">First</div>
        <div tabindex="1">Second</div>
        <div tabindex="2">Third</div>
      </div>
    )
  }
}

ReactDOM.render(<App />, document.getElementById('root'));
div:focus {
  color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>

Documentation

https://reactjs.org/docs/refs-and-the-dom.html

https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex

like image 69
AnonymousSB Avatar answered Sep 29 '22 11:09

AnonymousSB