Also available in: Español · Português · Français · العربية
JavaScript keycode tester
Shows every field a keydown event carries, and explains which of them the standard actually defines.
What is a keycode tester?
When you press a key, the browser fires a keydown event carrying several properties that all describe the same keystroke in different ways. A keycode tester shows you what those properties actually contain, which is the fastest way to find out what to check for in code — and the only way to be sure, because the answer depends on the browser, the operating system and the keyboard layout in front of you.
The three that matter are key, code and keyCode. The code names the physical key, in terms of where it sits on a notional US keyboard: the key next to the left Shift is KeyZ whether the letter printed on it is Z, Y or W. The key is what that keystroke produced — the actual character, or a name like ArrowLeft or Escape when there is no character. And keyCode is a number from a much older design that browsers still send.
The demonstration is on the page above, and it takes one hand. Press the 1 key: key is “1”, code is Digit1, keyCode is 49. Now hold Shift and press it again: code is still Digit1, keyCode is still 49, and key has become “!”. Two different characters, one physical key, and a number that cannot distinguish them.
How to use it
- Click the box, then press a key. The box only listens while it has focus, so nothing is captured behind your back. Every field of the event appears immediately, with the last eight presses kept underneath so you can compare two keystrokes side by side.
- Try a pair that differs by a modifier. 1 and Shift+1, or the semicolon key with and without Shift. Watch the key field change while code and keyCode stay where they were — that is the whole distinction, visible on one keyboard.
- Look up a code in the tables underneath. The two tables are the specification's own. Search by name or by number; codes the standard lists under two different characters are flagged, because those are exactly the ones keyCode cannot resolve.
keyCode was never a standard, and the spec says so
It is usually said that keyCode is deprecated. That is not quite what happened, and what did happen is more interesting. Section 7 of the UI Events specification, where these properties are described, is marked non-normative, and says of them that they “were never formally specified and the current browser implementations vary in significant ways”. The specification “does not normatively define” them at all. They are written down only so that what browsers already do is recorded somewhere.
The reason given is that it is too late to fix. Formalising the legacy attributes “would risk breaking as much content as it would fix or enable”, because so much existing code detects the browser and acts accordingly. The specification adds that these attributes are “not suitable for international usage, nor do they address accessibility concerns”, and that authors should use key instead.
Then it does something unusual: it publishes two tables describing what browsers agree on, and splits them by how much it is willing to claim. One lists codes that “do not usually change with keyboard layouts on desktop systems” — note “usually”, which is the specification's own hedge. The other lists punctuation that “MAY change virtual codes between keyboard layouts”, where browsers report the US English number because older code expects it.
The second table contains the sharpest evidence on this page, and it needs no key press at all. Eleven of its codes are listed twice — once for the unshifted character and once for the shifted one. 186 is both Semicolon and Colon. 187 is both Equals sign and Plus. 222 is both the single and the double quote. The ambiguity is not a browser bug or an edge case; it is printed in the standard.
Honest limits
This page can only tell you what your browser, on your operating system, with your current keyboard layout, sends right now. That is genuinely useful — it is the machine you are debugging on — but it is not a general answer. If you need to know what a French AZERTY keyboard sends for a particular physical key, no tester running on your machine can tell you; the code value is defined against a notional US layout precisely so that it does not vary, and everything else does.
The box only listens while it has focus, and that is deliberate rather than a limitation. A page that captures every keystroke regardless is unpleasant, and it breaks the browser's own shortcuts. For the same reason Tab is not captured unless you ask: holding Tab is how a keyboard user leaves the box, and trapping it silently would strand them.
Some keys cannot be captured by a web page at all, whatever it does. The browser and the operating system take a layer first, so a key combination bound to closing a window, switching applications or opening a system menu never reaches the page. That is not something a tester can work around, and any page claiming otherwise is testing something else.
Dead keys are worth knowing about if you type an accented language. On many layouts an accent key produces no character on its own — it modifies the next one — and the browser reports key as “Dead”. The tester labels those rather than showing an empty value, because an empty key field looks like a bug when it is the correct answer.
Finally, the tables here are the specification's, not a census of everything a browser might send. Most key codes appear in neither table, and the page says so rather than inventing a status: the standard describes only the values it has observed browsers agreeing on.
Why is it free?
Because it costs nothing to run. Everything happens in your browser — the keystrokes are read and displayed locally, nothing is sent anywhere, and there is no account.
The tables are extracted from the specification by a script kept in the repository, and the tests re-extract them and compare, so a drift between what this page shows and what the standard prints fails the build rather than reaching you. The specification's own typo in one key name is preserved deliberately, as proof the table was read rather than retyped.