Wondering about keyboard events: What they are, when to use them, when to not use? Me too.
There’s a lot of information out there on browser-based keyboard events, but I couldn’t find practical advice to my questions in a single, coherent post so I thought I’d write some posts on the subject, starting with this one. I hope to provide you (and future me) with solid footing and helpful information. May our future selves spent less time debugging and more time making wonderful experiences for our users.
The first bit of practical advice I want to touch on is that keydown
is likely the only keyboard event we need. The others, who needs them? Not us! Okay, maybe keyup goes on the shelf just in case, but surely keypress can be tossed out.
Why?
Let’s take a look starting with understanding what keyboard events exist today.
What are the keyboard events?
Here are the three keyboard events supported by all of the major browsers, in the order they are fired:
-
keydown
– fires when any key is pressed down, fires first, and always before the browser processes the key (e.g. inserting text, moving focus, etc). -
keypress
– fires when a key that produces a character value is pressed down, fires afterkeydown
, and before the browser processes the key. -
keyup
– fires when any key is released, fires last, and the browser processes the key.
Each of these events are cancelable and bubble up the DOM, but they’re not all equally useful.
Keydown is the only event you need to use
In my experience, keydown
is the only keyboard event worth using, keypress
can be ignored entirely, and keyup
is well suited for getting dusty on the shelf.
Why?
Let’s take a look.
Reasons for using keydown
Key coverage
Keydown
fires for any key so it’s going to give you the most coverage of keys being pressed. For example, it will fire for a character producing key like “f”, a modifier key like “Shift”, function keys, etc. You’ll never miss a keyboard event for a key that is pressed with keydown
.
Cancelable
Another reason for keydown
is that it fires before the browser processes the key so you have the opportunity to cancel it and/or stop it from bubbling up thru the DOM. If you don’t want to allow the letter “f” to be inserted – no problem – just cancel it using the event’s preventDefault
method. If you don’t want the event to propagate out (aka bubble up thru the DOM) then you can stop that by using the event’s stopPropagation
method.
Consistent across browsers
Another reason for using keydown
is that it fires consistently across browsers. This is important because as you’ll see soon this isn’t always the case for its closely related event: keypress
.
Speaking of keypress
, let’s look at why we want to avoid keypress
next.
Reasons for avoiding keypress
Lacks key coverage
Keypress
fires after keydown
, but still before the browser processes the key (e.g. inserting a character, moving focusing, submitting a form, etc). You can cancel and stop bubbling of keypress
events just like you can keydown
events, but keypress
only fires for a subset of keys – keys that produce character values – whereas keydown
fires on all of the keys. So modifier keys like Shift
, Control
, Alt/Meta
, function keys, etc won’t fire keypress
events.
This can put you in a situation where you’re needlessly debugging keypress
for not firing events or where you’re managing both keypress
and keydown
events. Why have two methods of capturing key events when one will do? Just use keydown
.
Inconsistent across browsers
If you’re still not convinced here’s another reason to avoid keypress
: It’s not fired consistently across browsers. What?! It’s mind boggling I know, but Firefox will fire a keypress
event when Tab
or any of the arrow keys are pressed , but no other browser will do this. Not Safari. Not Chrome. Not Opera. Not even IE.
Deprecated
A big reason to avoid keypress
, and maybe I should have led with this, is that keypress
is deprecated in the current W3C UI Events specification:
The keypress event type is defined in this specification for reference and completeness, but this specification deprecates the use of this event type.
The W3C specifications are sometimes a little ahead and sometimes a little behind browser implementation so somewhere down the road this may mean that browsers will do away with keypress
. It’s not likely anytime soon though. It’s usage is too prevalent in web sites and applications that have been built between the mid-nineties and now. But, it is a good indicator that we should all stop using it moving forward.
RIP keypress
.
With keypress
out of way let’s move onto why keyup
is best left to the sit on the shelf, collecting dust.
Reasons for shelving keyup
Let’s face it: keyup
is fairly meaningless.
Keyboard events, keydown
and keyup
, are independent from each other. In fact, they sandwich the browser performing the action that the user would see (e.g. inserting text, deleting text, focusing the next focusable element, etc.)
No default action
If you cancel a keydown
event it will prevent the browser from performing that action. But, it will not prevent keyup
from firing when the key is lifted. Keyup
is its own event. Now, just like keydown
you can also cancel keyup
, but it’s pointless. There is no default action associated with keyup
. The only time you’d need to cancel it is if there was custom keyup
handlers you wanted to prevent from being called.
Unless you really want to know that the user has lifted their finger from the key they have pressed – real or simulated – keyup
really doesn’t have much to offer. A fine dust collector it makes.
And in the off chance you find a need for it, it’s right there, waiting to be used.
Avoid mixing keydown and keypress
Keyboard events are independent events except when they’re not. And with keydown
and keypress
they’re not. Eleven times out of ten this makes mixing and matching keyboard events unnecessarily complicated.
If you’re thinking of using both keydown
and keypress
I want to give you a word of discouragement: Don’t. If you are currently using them then the next time you’re in that code consider moving the keypress
code over to akeydown
event handler, and then promptly deleting the keypress
handler.
Not only is the use ofkeypress
portentous given that it’s deprecated, it also creates more work for you. Anything you can do with keypress
you can do with keydown
. It’s much simpler to have only one type of event to worry about. This mitigates complication caused by things like browsers inconsistently firing keypress
and having to account for this in application code.
And you shouldn’t really even be using keypress
. You read the above section – Reasons for not using keyup – right? Let keypress
fall into the obscurity of history.
Keydown and keyup support complex interactions
One nice thing about the keydown
and keyup
that is not present with keypress
is the ability to support more complex interactions between the application and the user. If you’re a Slack user you likely have pressed Ctrl-/
or Cmd-/
to toggle the shortcut panel. Side note: Slack is packaged as a native app, but it’s really an browser-based app served inside of an Electron wrapper.
In reviewing this post my colleague Ben Beckwith brought this up in some feedback. He even shared a simple example to illustrate this point:
Say you want functionality like the Slack shortcut panel. You want a user to be able to press
Cmd-/
to toggle a pop-up box that showcases the available shortcuts to use in the application. In this situationkeypress
wouldn’t be relevant so you’d need to use eitherkeydown
orkeyup
.
This example, as contrived as it may be, is a really great example for the usefulness of keydown
and keyup
. As for keypress
, it gets another nail in the coffin.
Carry on keydown
If you’ve read this post then hopefully you’ve came to the same conclusion: keydown
is a keeper, keypress
is be tossed out, and keyup
goes on the shelf. If you’re not convinced (or re-affirmed), don’t hesitate to tweet at me. I’m always up for incorporating new perspectives and information into my own thinking.
And if you’re looking for more information on using these events, their APIs, and their nitty gritty specification details here are a few handy references:
Here are a few links to the Mozilla Developer Network:
- keydown event on the MDN.
- keypress event on the MDN.
- keyup event on the MDN.
- W3C DOM Level 3 / UI Events
In follow-up posts we’ll take a look at jumping cursors and the prevalent return false
statement that shows up in so many event handlers.
Until then, happy coding!