Life After KeyCode

May 21, 2021

Over the years, I wrote a bunch of quick JavaScript apps with code similar to:

document.addEventListener("keydown", ev => {
  // ESC
  if (ev.keyCode === 27) {
     // ...
  }
  // Enter
  if (ev.keyCode === 13) {
     // ...
  }
  // ...

but I found out recently that keyCode is deprecated:

deprecation warning from MDN

What now?

There are better options! Let’s have a quick look at available KeyboardEvent properties:

document.addEventListener("keydown", (ev) => {
  console.log({
    code: ev.code,
    key: ev.key,
    keyCode: ev.keyCode,
    which: ev.which,
  });
});

and try pressing:

screenshot of keydown properties

Observations: keyCode and which

Both keyCode and which are deprecated.

Also, I can’t see a difference in values (using Chrome 90), but it seems like it might differ between browsers… And having worked with them before, and their numeric outputs, I would say that’s good riddance.

Observations: code

The other difference that stood out was the handling of shift. Both upper/lower n registered as KeyN for the code property. That would put the responsibility of checking the shiftKey property ourselves, to differentiate the events. 😩

That’s a bit more surprising for keys we don’t typically associate as “being the same”:

bracket, but not curly bracket...

Are ] and } both “BracketRight”, with only a difference in shift? 🤔
That doesn’t sound right to me…

(is # a shifted Digit3? … on all keyboards, all the time?)

Observations: key

Finally, the key property seems to be the way to go.

The downside would be differentiating a left/right with shift/ctrl/alt/meta – a case that I don’t usually handle. (though something to keep in mind)

If you’re wondering exactly what you’re going to get when pressing a key, check out the KeyboardEvent Key Values page.

Sidenote: shift/ctrl/alt/meta

KeyboardEvent has boolean properties for “control keys”:

which I haven’t historically been great at keeping track of… It’s easy to trigger on the a key, but to forget to check the metaKey status and prevent cmd-a from triggering normally. (usually due to an eager preventDefault). Which leads me to…

Quick tip: key-combinations

Since I stumbled on the keyCode deprecation, I’ve been refactoring my apps. I’ve been happy with this snippet of code:

document.addEventListener("keydown", ev => {
  const keys = [
    ev.metaKey && "Meta",
    ev.ctrlKey && "Ctrl",
    ev.altKey && "Alt",
    ev.key,
  ].filter((v) => v).join("-");
  if (keys === "a") {
     // ...
  }
  if (keys === "Meta-a") {
     // ...
  }
});

which keeps these boolean cases more explicit and, thankfully, mutually exclusive.

Some things to consider:

Discuss on Twitter