A good[ish] website
Web development blog, loads of UI and JavaScript topics
Here’s how to listen to more complex keyboard input with JavaScript.
Usually, it’s better to listen keyup
, because with keydown
it’s easy to unleash a deluge of events possibly bogging up your site.
const handleKeyboard = event => {
if (event.key === '/') console.log('The ’/’ key was pressed')
}
document.addEventListener('keyup', handleKeyboard)
This is roughly what the event contains when an alt key was pressed:
{
altKey: false,
ctrlKey: false,
metaKey: false,
shiftKey: false,
charCode: 0,
code: "AltLeft",
isComposing: false,
key: "Alt",
keyCode: 18,
location: 1,
repeat: false,
type: "keyup",
which: 18,
// Unrelated properties redacted for brevity.
}
Here’s a quick rundown what each of them do:
KeyboardEvent.altKey
KeyboardEvent.ctrlKey
KeyboardEvent.metaKey
KeyboardEvent.shiftKey
KeyboardEvent.charCode
👎KeyboardEvent.code
AltLeft
or AltRight
KeyboardEvent.isComposing
compositionstart
and compositionend
. Composition session is when a character is required to be entered using multiple keystrokes, like Chinese characters or accented characters like "à": alt+` followed by an a.KeyboardEvent.key
KeyboardEvent.keyCode
👎KeyboardEvent.location
KeyboardEvent.repeat
keydown
event.KeyboardEvent.shiftKey
KeyboardEvent.type
I’m using Cmd+/ (or Ctrl+/) as an example here (which opens the search on this site btw). When doing key-combos it’s good to listen to the keydown
event:
const handleKeyboard = ({ repeat, metaKey, key }) => {
if (repeat) return
if ((metaKey || ctrlKey) && key === '/') console.log('’Cmd+/’ was pressed')
}
document.addEventListener('keydown', handleKeyboard)
See the bail on the repeat
, without that, there would be a torrential flood of events firing when the key is kept in a pressed state, which might bog up your app.
This little demo toggles a search bar on the header with Cmd+/ or Ctrl+/:
const [searchOpen, setSearchOpen] = React.useState(false)
const handleKeyboard = ({ repeat, metaKey, ctrlKey, key }) => {
if (repeat) return
// Handle both, `ctrl` and `meta`.
if ((metaKey || ctrlKey) && key === '/') setSearchOpen(prev => !prev)
}
React.useEffect(() => {
document.addEventListener('keydown', handleKeyboard)
// Important to remove the listeners.
return () => document.removeEventListener('keydown', handleKeyboard)
})
Notes on the above code:
metaKey
and ctrlKey
so it works on Windows and Mac.componentWillUnmount
method.If you want to, say, open the search when s and e are pressed, you need to be a bit more clever. You can keep a log of the keys pressed on keydown
and then clear the log on keyup
:
const keyLog = {}
const handleKeyboard = ({ type, key, repeat, metaKey }) => {
if (repeat) return
if (type === 'keydown') {
keyLog[key] = true
// When "s" and "e" are pressed.
if (keyLog.s && key === 'e') setSearchOpen(prev => !prev)
}
// Remove the key from the log on keyup.
if (type === 'keyup') delete keyLog[key]
}
React.useEffect(() => {
const events = ['keydown', 'keyup']
events.forEach(name => document.addEventListener(name, handleKeyboard))
return () =>
events.forEach(name => document.removeEventListener(name, handleKeyboard))
})
Here’s a demo for that one:
Comments would go here, but the commenting system isn’t ready yet, sorry.