DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’»

DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’» is a community of 966,904 amazing developers

We're a place where coders share, stay up-to-date and grow their careers.

Create account Log in
Cover image for Bringing `KeyboardEvent.key` and `KeyboardEvent.keyCode` Altogether for the Best Keyboard Interaction Experience
Taufik Nurrohman
Taufik Nurrohman

Posted on

Bringing `KeyboardEvent.key` and `KeyboardEvent.keyCode` Altogether for the Best Keyboard Interaction Experience

Photo by Sathesh D from Pexels

In ancient times, we were depending on the KeyboardEvent.keyCode property for so long to detect which key we were pressing on the keyboard:

node.addEventListener('keydown', e => {
    if (13 === e.keyCode) {
        // Do something with `Enter` key
    }
}, false);
Enter fullscreen mode Exit fullscreen mode

Years have passed and the diversity of today’s keyboard layout makes me even more horrified. Most of us still using that old method to support the en-US keyboard standard only (either consciously or not), which then gives us the possibility of unexpected results on other keyboard layouts. For example, on the Russian keyboard layout, the , key stands together with the Π‘ key, so that when we have a custom keyboard interaction that requires the detection of comma character to perform certain actions, then usually that action will also be triggered when we actually want to type Π‘. We literally has ignored other keyboard layouts either because of lack of knowledge or because we feel that it just too much to be able to support all of them.

Russian Keyboard
Russian Keyboard

Long story short, the KeyboardEvent.keyCode is now deprecated. We now have a better alternative: KeyboardEvent.key that displays whatever characters we type on an input without caring about the type of keyboard layout that we are currently using. It also works on non-printable characters such as that Enter and Backspace key which will produce 'Enter' and 'Backspace' string accordingly.

node.addEventListener('keydown', e => {
    if (',' === e.key) {
        // Do something with `,` key
    }
}, false);
Enter fullscreen mode Exit fullscreen mode

It’s so cool that I want to pee here. Unfortunately, this feature is still not widely supported, especially on mobile devices. So it’s better to use both of them to get the best results:

node.addEventListener('keydown', e => {
    let key = e.key,
        keyCode = e.keyCode;
    if (key && ',' === key || keyCode && 188 === keyCode) {
        // Do something with `,` key
    }
}, false);
Enter fullscreen mode Exit fullscreen mode

Since KeyboardEvent.keyCode value mostly in line with character codes from the ASCII table, some people also like to use this method. Although this method will not work on non-printable characters, at least we try to give the best results with KeyboardEvent.key as priority:

node.addEventListener('keydown', e => {
    let key = e.key || String.fromCharCode(e.keyCode);
    if (',' === key) {
        // Do something with `,` key
    }
}, false);
Enter fullscreen mode Exit fullscreen mode

For devices that support KeyboardEvent.key, a key that cannot be identified will return 'Unidentified'. This case becomes very strange when I try to check it on my mobile device as it always produces 'Unidentified' on any key:

Google Chrome on Android Device
Chrome 78.0.3904.108

Normally, when an object property does not exists (no key property means no support for KeyboardEvent.key), it should return undefined. But it wasn’t. This leads me to conclude that KeyboardEvent.key feature might already exist on my device, it’s just that it’s not working properly.

Maybe, the last way that looks pretty hacky but just works in an urgent situation is to check the last character that we entered. But since the last character don’t exist (yet) as the keydown event is being performed, we need to delay the action in a fraction of a millisecond before retrieving the incoming characters:

node.addEventListener('keydown', e => {
    // First try
    if ( /* … */ ) {
        // Do something with `,` key
    } else {
        setTimeout(() => {
            // Second try
            if (',' === node.value.slice(-1)) {
                // Do something with `,` key
            }
        }, 1);
    }
}, false);
Enter fullscreen mode Exit fullscreen mode

You can also use the Text Selection Range API to handle this if you want to check the last character exactly before the caret, but it’s just too much, especially for HTML elements with contenteditable attribute (they simply have different API). And if you decide to use it, then it might be more beneficial for you to detect those characters through the incoming values and so forget about the KeyboardEvent.key feature detection.

By the way, the following is a project that I have made using the above concept. It beautifies your text input into a β€œtags” input, sort of. It also has better keyboard interaction support such as removing tags using Delete and Backspace keys. You can also navigate to other tags using the arrow keys:

GitHub logo taufik-nurrohman / tag-picker

Better tags input interaction with JavaScript.

Tag Picker

Better tags input interaction with JavaScript.

Tag Picker

Tag Picker is a simple JavaScript application that aims to provide better experience for users in adding and removing comma-separated list of words.

Demo and Documentation

Contribute

  • Please do not make pull requests by editing the files that are in the root of the project. They are generated automatically by the build tool.
  • Install Git and Node.js
  • Run git clone https://github.com/taufik-nurrohman/tag-picker.git
  • Run cd tag-picker && npm install
  • Edit the files in the .github/src/- folder.
  • Run npm run pack to generate the production ready files.

Release Notes

3.1.12

  • Fixed a bug that caused the original input value not updated due to the cached $.tags value on a variable.
  • Maintenance.

3.1.7

  • Included CSS and SCSS files to the NPM package.
  • Included custom HTML5 <tag-picker> element script to the NPM package.

3.1.6

  • Added custom setter and getter for the HTML5 <tag-picker> element so that it…

Top comments (0)

Need a better mental model for async/await?

Check out this classic DEV post on the subject.

β­οΈπŸŽ€ JavaScript Visualized: Promises & Async/Await

async await