Using onKeyDown on a certain element will require focus to work as intended.
We can make your MdOutlinePause component focus-able by adding the tabindex attribute. That will allow you to give the icon focus by hitting tab or by clicking on it. The element would look something like this:
<MdOutlinePause tabIndex={0} onKeyDown={handleKey} />
If you want to detect the key event without having to focus the element, you will need to attach an event listener. We can do this with useEffect so this happens onMount, and we'll attach the event listener to the window so it works regardless of which element has focus:
/// Don't copy and paste this - see below
useEffect(() => {
window.addEventListener("keydown", handleKeyPress);
});
}, []);
/// Don't copy and paste this - see below
This allows you to detect the keyboard event, which is great, but there's an issue: the eventListener gets added again whenever the page mounts, but is never removed. So you will likely run into issues of your function getting called multiple times on each keyPress.
We can fix this by removing the event listener in the return from useEffect. This is how we specify a function to let the useEffect clean up after itself. This ensures that our useEffect is never adding more than one "keydown" event listener at a time:
useEffect(() => {
window.addEventListener("keydown", handleKeyPress);
return () => {
window.removeEventListener("keydown", handleKeyPress);
};
}, []);
Here's a full example on codesandbox
This works great if you don't need to access state in your handleKeyPress function.
It is a common use case to need to do something with state variables when the user does a certain action, and if we need to access updated state then we run into a problem: we attached handleKeyPress to the event listener onMount and the function never gets updated, so it will always use the initial version of state. This codesandbox illustrates the issue.
We can fix this by adding handleKeyPress to the dependencies array for useEffect, but this results in our event listener being removed and re-added on every render since handleKeyPress will be updated on each render. A better solution is to use the callback pattern with our handleKeyPress so that it is only updated when actually necessary (when the state it depends on is updated). We also want to add handleKeyPress to our useEffect dependency array so we create a new event listener when the handleKeyPress function changes:
const handleKeyPress = useCallback((event) => {
// do stuff with stateVariable and event
}, [stateVariable]);
useEffect(() => {
window.addEventListener("keydown", handleKeyPress);
return () => {
window.removeEventListener("keydown", handleKeyPress);
};
}, [handleKeyPress]);
Now everything updates appropriately! Here's a full example of this on codesandbox.
There's one more solution which lets you access state in the simplest way possible. The downside is that the only state variable you have access to (with updated values) will be the state variable you are updating, so this solution is situational. To access other state variables, you'll have to use the solution above.
By passing a function to useState, we can access the previous state as the first argument of the function. This allows for a much simpler approach, shown below and in this codesandbox.
const [text, setText] = useState("");
const handleKeyPress = event => {
setText(previousText => `${previousText}${event.key}`);
};
useEffect(() => {
window.addEventListener("keydown", handleKeyPress);
return () => {
window.removeEventListener("keydown", handleKeyPress);
};
}, []);
Answer from Andrew Hulterstrom on Stack OverflowFiring a button onKeyUp?
How to detect which React component triggers onKeyUp event?
Add `onKeyUp` and` onKeyDown` support?
reactjs - handling `onKeyUp` for a div - Stack Overflow
Videos
Currently have a button that I want to fire using the Enter key in a class component but for some reason it's not working. Any ideas?
handleKeyUp(event) {
if (event.keyCode === 13) {
console.log('Enter key has been pressed')
}
}
render() {
return(
<div>
<button
onKeyUp={ this.handleKeyUp }
>
Submit
</button>
</div>
);
}
» npm install react-native-keyevent
You have to capture the keypress then in body/window level. Table element doesn't have input focus so you can't capture the keys from table (without input element).
var cmdDown = false;
document.body.addEventListener('keydown', function(event) {
var key = event.keyCode || event.charCode || 0;
if ([91,93,224,17].indexOf(key) !== -1) {
cmdDown = true;
}
console.log('CMD DOWN: ' + cmdDown.toString());
});
document.body.addEventListener('keyup', function(event) {
var key = event.keyCode || event.charCode || 0;
if ([91,93,224,17].indexOf(key) !== -1) {
cmdDown = false;
}
console.log('CMD DOWN: ' + cmdDown.toString());
});
Simple Example
I believe best practice here is to add an event listener to document and modify your element (e.x. table) accordingly. Extending u/Hardy's answer with a full React component:
class MyComponent extends React.Component {
// Using an arrow function. Alternatively, could bind() this
// function in the component's constructor
keydownHandler = (event) => {
// Add logic, e.x. check event.keyCode to see
// if CMD is pressed and then update state
}
componentDidMount() {
document.addEventListener("keydown", this.keydownHandler);
}
componentWillUnmount() {
this.removeEventListener("keydown", this.keydownHandler);
}
render() {
<div>Hello World</div>
}
}
Alternative
As others have noted, there are challenges in using keyboard events that are bound to non-input elements, as browsers require those elements to be in focus in order to invoke the bound callbacks. Another approach that seems to work is to set the tabindex property of the component to bring the element in focus. From u/burak's answer:
render() {
<div onKeyDown={this.keydownHandler} tabindex={-1}>Example</div>
}
This has the benefit of connecting into React's Synthetic Events, that is "a cross-browser wrapper around the browser’s native event." However, when modifying the tabindex property it's important to be mindful that this could change the order of focusable elements, and affect a user's ability to navigate your site with their keyboard or accessibility software. Some users report that setting tabindex to -1 resolves this issue (see comments in previous link).