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.
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 after
keydown, 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.
Let’s take a look.
Reasons for using keydown
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
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
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, let’s look at why we want to avoid
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
keypressonly fires for a subset of keys – keys that produce character values – whereas
keydown fires on all of the keys. So modifier keys like
Alt/Meta, function keys, etc won’t fire
This can put you in a situation where you’re needlessly debugging
keypress for not firing events or where you’re managing both
keydown events. Why have two methods of capturing key events when one will do? Just use
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.
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.
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.
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
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
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 a
keydown event handler, and then promptly deleting the
Not only is the use of
keypressportentous 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
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
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 situation
keypresswouldn’t be relevant so you’d need to use either
This example, as contrived as it may be, is a really great example for the usefulness of
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!