Reputation: 751
I am trying to detect a key press anywhere on the page in an app built with React.
I remember it being quite easy in jQuery, but I wanted to see if it could be done in React. I didn't want to make a 'frankenstein' project i.e. have some parts in react and some parts in jQuery, if at all avoidable.
So far I have:
export default function App() {
const handleKeyPress = (event) => {
console.log(event.keyCode);
}
return (
<div
onKeyDown={handleKeyPress}
tabIndex="0"
>
<Header page_num={100}/>
</div>
);
}
But it only seems to work when a user clicks on the actual div in the page, then presses a key.
I want the key press to be detected without the user having to click anywhere on the page.
Upvotes: 13
Views: 14223
Reputation: 38767
You can use useEffect
hook to achieve this and adding an event listener to document
:
import React, { useEffect } from "react";
export default ({ name }) => {
useEffect(() => {
function handleKeyDown(e) {
console.log(e.keyCode);
}
document.addEventListener('keydown', handleKeyDown);
// Don't forget to clean up
return function cleanup() {
document.removeEventListener('keydown', handleKeyDown);
}
}, []);
return <div>Keydown</div>;
};
Here is an example in action.
Assuming the <div>
is focused via tabindex
or similar, you'd be able to see see in the keydown handler that e.target
would be the <div>
. You can also wrap the functionality in another component and in it's keydown handler check if the keydown was executed on that element instead of outside using contains.
Here is another example that uses contains
to check if the event target is within the div ref
:
import React, { useEffect, useRef } from "react";
function Hello({ onKeyDown }) {
const ref = useRef();
useEffect(() => {
function handleKeyDown(e) {
// check if keydown was contained in target div
if (!ref.current || ref.current.contains(event.target)) {
return;
}
// Emit event to parent component
onKeyDown(e);
}
document.addEventListener("keydown", handleKeyDown);
return function cleanup() {
document.removeEventListener("keydown", handleKeyDown);
};
}, []);
return (
<div ref={ref} tabIndex="0">
foo bar baz
</div>
);
}
export default Hello;
Hopefully that helps!
Upvotes: 31