clubmate.fi

A good[ish] website

Web development blog, loads of UI and JavaScript topics

Listen key combinations with JavaScripts

Filed under: JavaScript— Tagged with: event

Here’s how to listen to more complex keyboard input with JavaScript.

A basic example

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)

Anatomy of the KeyboardEvent

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
A boolean telling you if an alt key was pressed when the event was initiated.
KeyboardEvent.ctrlKey
A boolean telling you if an ctrl key was pressed when the event was initiated.
KeyboardEvent.metaKey
A boolean telling you if a Meta key was pressed when the event was initiated. In Mac this would be ⌘ Command and in Windows it would be the ⊞ Windows key.
KeyboardEvent.shiftKey
A boolean telling you if a shift key was pressed when the event was initiated.
KeyboardEvent.charCode 👎
Deprecated, but it returns the Unicode value of the character pressed.
KeyboardEvent.code
Returns the name of a physical key on the keyboard, not the character generated by pressing a key, meaning it’s immune to keyboard layouts or modifier keys. You can get really granular with this, for example you can know which alt key was pressed for example AltLeft or AltRight
KeyboardEvent.isComposing
A boolean value indicating whether the event was fired during an open compositions session e.g: between 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
Returns the name of the key pressed, including the state of any modifier keys.
KeyboardEvent.keyCode 👎
Deprecated, but it’s still widely used (as of writing this). It returns the numerical value of of the key.
KeyboardEvent.location
The location can have 4 values: 0, 1, 2, and 3. The location is 0 if a key has only one version (i.e. "g"), 1 if it was the left-hand version of a key (like alt), 2 if right-hand side, and 3 if the key is part of a numeric keypad.
KeyboardEvent.repeat
A boolean property signaling whether the key is pressed in during a keydown event.
KeyboardEvent.shiftKey
A boolean telling if a shift key was pressed when the event was initiated.
KeyboardEvent.type
Not purely a keyboard event property. A string value simply representing the event name. Handy when listening to multiple events at the same time.

Listening key combos: Cmd or Ctrl + key

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.

Key-combo example using React

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:

  • Remember to handle both metaKey and ctrlKey so it works on Windows and Mac.
  • Also remove the events when you’re done with them: using function components you return a function and run the cleanup inside that. It’s equivalent to the good old componentWillUnmount method.

See a Demo ZEOdZGz

Listening to multiple keys that are not meta, ctrl, or alt

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:

See a Demo zYBVQBp

Comments would go here, but the commenting system isn’t ready yet, sorry. Tweet me @hiljaa if you want to make a correction etc.

  • © 2021 Antti Hiljá
  • About
  • Follow me in Twatter → @hiljaa
  • All rights reserved yadda yadda.
  • I can put just about anything here, no one reads the footer anyways.
  • console.log('Smash the patriarchy!')
  • I love u!