Boy, was it hard to implement proper keyboard shortcuts
Tags: a11y, html, polyfill, browser
Published: 2021-01-10 02:14:48

I'm currently implementing a complete redesign of our primary administration interface. This web application is used by our customer service every day to read, write and process heaps of information and complex data structures. When you're designing an interface for such trained users, priorities shift a great deal. **These users prefer speed over simplicity,** so you start to seriously optimize things like navigation. And the easiest, maybe even the most important way to speed up navigation is by providing **keyboard shortcuts.** Most websites don't really use custom keyboard shortcuts because they take too much time to learn. But for users who spend many hours a day working with a web application, keyboard shortcuts are indispensable. And so my journey began...

{% spoiler TL;DR %} I built a polyfill for the `accessKeyLabel` property that reveals the keyboard shortcut assigned by the browser and based on the `accessKey` property assigned to an interactive element. Browsers use different shortcuts for this and the `accessKeyLabel` property is the best way to improve the discoverability of custom shortcuts in web applications. Native support is missing in Chrome, IE and Edge. My AccessKeyLabelPolyfill is bridging the gap with less than 1 KB. [GitHub](https://github.com/tillsanders/access-key-label-polyfill) | [Demo](https://tillsanders.github.io/access-key-label-polyfill/) {% endspoiler %}

# Using the `accesskey` property to quickly add keyboard shortcuts

Since HTML 4, we've had the power to add custom keyboard shortcuts to our webpage using the [`accesskey`](https://developer.mozilla.org/de/docs/Web/HTML/Globale_Attribute/accesskey) property.

```html
<button accesskey="d">Do crazy stuff</button>
```

Simply by adding this property to a button, I've set up a keyboard shortcut. In most browsers, pressing `Ctrl` + `Alt` + `D` will now trigger this button. Great! So I just added this to a number of buttons in our application and called it a day? Unfortunately not. See, what modifier keys (`Ctrl`, `Alt`, `Shift`, etc.) will be combined to a shortcut is not standardized. And I wish that was the only problem.

# Browsers don't use the same key to make the shortcuts

So, as I said, most browsers use `Ctrl` + `Alt`. At least on macOS. Except for Firefox before version 14. Back then, it only used `Ctrl`. On Windows, the same browsers generally use only the `Alt` key. Except for Firefox, which seems to strive for cross-platform consistency. Nice. These are, however, only the browsers whose behaviour was documented on MDN. As you know there are loads more. And at least some even allow to customise their behaviour. This means that the actual shortcut depends on the browser, it's version, your operating system and possibly your personal settings. But don't worry, it get's worse.

# Users are unaware of keyboard shortcuts on websites

Let's face it. Most people are completely dumbfounded when it comes to keyboard shortcuts. If you're ever trying to impress people, just show them the `Tab` key. But when they're working with the same application every day, we should try to educate them to help speed things up. So now that we have keyboard shortcuts thanks to `accesskey`, how can we make them easily discoverable?

# Proven technique to indicate keyboard shortcuts

For some reason, I'm seeing this technique less and less in modern systems – probably due to aesthetic reasons. But it has been around for decades and I doubt that it get's any more elegant than this. The idea is simple and every little as space-saving as it is helpful: **just underline the character that is the access key.**

```html
<button accesskey="d"><u>D</u>o crazy stuff</button>
```

By using a consistent scheme (like `Ctrl`+ `Alt` / `Alt`) and underlining the access key, we give users a subtle hint or reminder which character provides access to a specific action. Neat.

# Underlining the access key is not enough

We surely can improve the discoverability of our shortcuts even more. Right now, the biggest issue is that users are probably unfamiliar with the default keyboard shortcut of their browser. So why don't we add a small reminder. For big buttons with enough space, we could add a small text below. For others, we could add tooltips or use the `title` attribute.

```html
<button accesskey="d">Do crazy stuff</button>
<small>Hint: Use Ctrl + Alt + D to quickly access this button!</small>
```

Great! But as we learned in the beginning, browsers use different modifier keys for our shortcuts. How do we handle this?

# The `accessKeyLabel` API reveals the exact shortcut

Thankfully, the [`accessKeyLabel`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/accessKeyLabel) API of HTML 5 will tell us the exact keyboard shortcut the browser assigned to our button. That's great! We can access this property in a Vue.js component and add it to our hint easily. No magic required.

# Chrome does not support `accessKeyLabel`

Well, I must admit – I didn't see that one coming. While `accesskey` is supported perfectly, Chrome, Internet Explorer (okay, no surprise...), Edge, Safari for iOS < v13 and more don't (yet) support `accessKeyLabel`. [That's a bummer.](https://caniuse.com/?search=accessKeyLabel) Firefox and Safari for macOS however, have good support. But it's still not enough to rely on.

# Use my polyfill

As it turns out, there is a [ticket](https://bugs.chromium.org/p/chromium/issues/detail?id=393466&q=accesskeylabel&can=2) in the bug tracker of the chromium project that's been calling to add support for the `accessKeyLabel` property since 2014. Unfortunately, other things seem to have a higher priority, so until native support arrives in all major browser, we need a polyfill.

{% details What is a polyfill? %} A polyfill is a script that patches native functionality that has not yet arrived in certain browsers or will not arrive because of old age. Polyfills generally aim to provide the exact same functionality and API as the original specification. Some things, however, can only be partially implemented using polyfills. What's great about polyfills is that they allow us to use new technologies without needing to worry too much about "older" browsers. The disadvantage is, of course, that we're adding more code to our website that might slow it down a little bit more. That being said, most polyfills are actually quite small.{% enddetails %}

My search for a polyfill was surprisingly unsuccessful. I stumbled upon a jQuery plugin, but wanted something vanilla JavaScript.

Sometimes, to provide great user experience and accessibility, you have to go to great lengths. I tend to do that. So here is my very first polyfill. It is vanilla JavaScript and weighs under 1 KB: 

{% github tillsanders/access-key-label-polyfill %}

# Installation and usage of the AccessKeyLabelPolyfill

You can install the polyfill using npm or yarn:

```sh
npm i access-key-label-polyfill
# or
yarn add access-key-label-polyfill
```

And then import and execute like this:

```javascript
import installAccessKeyLabelPolyfill from 'access-key-label-polyfill';
installAccessKeyLabelPolyfill();
```

# Reading the `accessKeyLabel`

I integrated this into a Vue.js button component that also has some neat methods to automatically underline the first occurrence of the `accessKey` in the button caption, but you might use it any way you like. You can read the documentation of the [`accessKeyLabel` property on MDN](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/accessKeyLabel), because the API of the polyfill is exactly the same. But it's quite simple, so here is an example:

```javascript
const label = document.querySelector('#button').accessKeyLabel;
```

The polyfill will first check if `accessKeyLabel` is supported natively and exit if so. Otherwise it will try to detect the browser and operating system and return the correct keyboard shortcut as a string that can be displayed in a `<small>` tag, a tooltip, or the `title` attribute. Get creative!

If you're using the polyfill with Vue.js, React, Svelte, Angular or other frameworks, remember to only load it once!

# Try the demo!

You can visit the demo to try the plugin right in your browser. The demo will also tell you wether the polyfill detected native support or not. [Try the demo!](https://tillsanders.github.io/access-key-label-polyfill/)

# The state of keyboard shortcuts in web applications

Today's odyssey into the `accessKeyLabel` property revealed to me the many issues we face regarding shortcuts in web applications. Not only are the shortcuts **not standardised** and support for the simple `accessKeyLabel` **API is missing in most browsers**, but I was unable to discover the shortcut in Chrome for Android. Maybe I was due to a lack of a proper Android tablet for testing or maybe `accesskey` is simply not supported. To me, it's unclear how access keys **might interfere with screen readers**, browser shortcuts or even other applications. There is also no standard on how browsers handle **conflicting access keys**. But what's easily **the biggest issue is usage**. It is rare to see a web application use these features, even the complex ones that would benefit greatly from it. By taking the time of writing and publishing this polyfill, I hope to make keyboard shortcuts in web applications more accessible to you all by bridging the gap in browser support.