Building hotkeys in React apps

kolot

Ivan Kolotilov

Posted on November 8, 2022

Building hotkeys in React apps

Introduction

Using hotkeys is a great way to let your web app users get more done faster.

It works even better for power users and complex internal applications where your users spend a lot of time, like systems for content editing, monitoring systems or support tools.

In this article, first, we'll look at some design aspects to keep in mind when implementing hotkeys in an app and ways to make hotkeys convenient for the end user. Then we will do basic hotkeys implementation and look at how to add hotkeys to React application.

Hotkey Integration Preparations

Stick to three hotkey development guidelines:

  • Discoverability: familiarise your users with hotkeys. Use onboarding, walkthroughs, labels or tooltips to help users learn about your hotkeys system
  • Memorability: hotkeys and key combos need to be simple and memorable
  • Compatibility: avoid situations where your hotkeys conflict with existing system-wide or browser shortcuts

1. Make a Plan

Define a list of actions demanding hotkey implementation. It is helpful to pursue a structured approach, starting with mapping out the user stories in your application and defining app sections. Then split your user stories into actions ranked by importance and usage frequency. Leveraging user feedback and analytics can be very helpful here. All the actions could be divided in two big groups:

  • Global actions include navigation between app parts and launching important functionality. Generally, it makes sense to implement it on the top level of the app (e.g. as a react wrapper component or context).

  • Contextual actions, such as controlling modal windows or popups, should be implemented at the relevant component level (modal window, multi-step form, etc.).

2. Pick the Hotkeys

Think of the hotkeys and key combos. Remember that they should be memorable and non-conflicting with browser or OS hotkeys.

  • Keep context and users in mind. What OS they are using, other running apps, preferred browser hotkeys, such as native browser search for content-rich websites.

  • Steer clear of the overloaded classic key combos
    Ctrl + N, Ctrl + O, Ctrl + S, Ctrl + P, Ctrl + W & Ctrl + C, Ctrl + Z, Ctrl + F
    Alt + F1, F2, F3…

  • Decide if you want to use

    • Single hotkeys
    • Combinations or
    • Sequences - keep in mind that they should not conflict with single hotkeys

Settling on one approach will simplify hotkeys for the users.

Single-key hotkeys are easier to use and remember, especially if they're assigned to actions corresponding with key letters. However, this allows for accidental keypresses and a smaller number of possible hotkeys. There are more options with combinations, but some of them will be already used by OS and browser hotkeys.

The sequences approach works for assigning lots of actions, giving you the biggest freedom of options and number of available combos. For example, it’s used in Gmail. But if you pick this route, avoid using single hotkeys since that will lead to conflicts and a poor UX. You can override browser hotkeys by calling event.preventDefault() but think twice before you do it as it can be super annoying to your users sometimes.

After deciding what hotkeys you will assign to your actions, go to your app and try to use them as if they are already there. This will put you in users' shoes and let you identify what works well and what could be improved.

3. Think About Informing the User

Find a way to implement hotkey information in your design. Some of the frequently used tools include:

Labels

Image description

Tooltips

Image description

Underlined letters in buttons corresponding to hotkeys

Image description

Hotkey maps
For the best discoverability and memorability, it’s great to add a hotkey map, i.e. a page or a modal window with the list of all available actions in the app.

If there are many hotkeys, a search with a filter may be added on top of the map. Here are some examples of hotkey maps:

  1. Pivotal tracker
  2. Trello
  3. Codesandbox

By the way, in all the examples above, users can see those hotkey maps by hitting a '?' key. You can consider following this best practice as well.

As a result, you have a list of hotkeys and informational design elements to get users up to speed. Now we can move on to implementation.

For internal app interfaces, which users think of as their main work tools, consider making hotkeys customisable so that users can reassign the keys. This could be useful for the most advanced users.

Implementing Hotkeys in React

Let’s dive into how hotkeys can be implemented in a React app, look into possible improvements and go over some popular hotkeys libraries that could be helpful to build hotkeys system for your app.

Adding Hotkeys

This is what the most basic TypeScript hotkey implementation looks like. All hotkeys implementations are based on event listener, attached either to the document object or a specific DOM node.

We can use keydownevent to track keyboard presses by the user. Note that we’ve added a check for the event.repeat property to neutralise double clicks.

You can always check out all keyboardevents properties on MDN.



export const setupHotkeys = () => {
 document.addEventListener("keydown", (event: KeyboardEvent) => {
   if (event.repeat) {
     return;
   }
   if (event.ctrlKey && event.key === "l") {
     // do what you want to do when CTRL + L is pressed 
   }
 });
};


Enter fullscreen mode Exit fullscreen mode

Hotkeys in a React App

Now let’s implement basic hotkeys as a hook for a React app.

We are using the useLayoutEffect hook and useRef hooks to recall the most up to date callback to avoid bugs. Here is a very nice article explaining how useLayoutEffect hook works just in case.

We’re also using the useEffect callback to attach the listener. Please note that we are removing the event listener in a function that gets returned by the useEffect hook. (Here is the documentation for useEffect hook). We do this to ensure we don’t leave the listener attached when the component is removed from dom - this is needed to avoid memory leaks.



export const useHotkeys = (
 key: string,
 callback: (event: KeyboardEvent) => void
) => {
 const callbackRef = useRef(callback);

 useLayoutEffect(() => {
   callbackRef.current = callback;
 });

 useEffect(() => {
   const handler = (event: KeyboardEvent) => {
     if (event.key === key) {
       callbackRef.current(event);
     }
   };

   document.addEventListener("keydown", handler);

   return () => document.removeEventListener("keydown", handler);
 }, [key]);
};



Enter fullscreen mode Exit fullscreen mode

Let’s now implement support for combos.

We start by adding an additional parameter, like a combination key or a modifier - Alt, Ctrl, Shift, and the meta key (Windows logo key or the Mac command key). To support the combination, we’ll add an additional check in the handler so that the app reacts only when the key is pressed in a combination with a modifier key.



type CombinationKey = "alt" | "ctrl" | "meta" | "shift";

export const useHotkeys = (
 key: string,
 combinationKey: null | CombinationKey,
 callback: (event: KeyboardEvent) => void
) => {
 const callbackRef = useRef(callback);

 useLayoutEffect(() => {
   callbackRef.current = callback;
 });

 useEffect(() => {
   const handler = (event: KeyboardEvent) => {
     if (
       (!combinationKey || event[`${combinationKey}Key`]) &&
       event.key === key
     ) {
       callbackRef.current(event);
     }
   };

   document.addEventListener("keydown", handler);
   return () => document.removeEventListener("keydown", handler);
 }, [key, combinationKey]);
};



Enter fullscreen mode Exit fullscreen mode

React Libraries for Hotkeys

There are lots of hotkey development libraries for React apps, one of the most popular ones being react-hotkeys-hook.

An example of how hotkey implementation works in this library:



import { useHotkeys } from 'react-hotkeys-hook'

export const Component = () => {
 useHotkeys('ctrl+j', () => {/* do something */});

 return (
   /* some jsx */
   )
}


Enter fullscreen mode Exit fullscreen mode

Here’s some other hotkey libraries to check out:

Conclusion

We looked at some ways of building and implementing hotkey systems in React apps. When developing hotkeys, our priority should always be usability and comfort. Well-designed hotkeys can save tons of time for your users and make them happy so it's worth considering hotkeys in your app.

If you found this interesting and want to know more, here are some cool articles on this topic that I've used while researching:

💖 💪 🙅 🚩
kolot
Ivan Kolotilov

Posted on November 8, 2022

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

Building hotkeys in React apps
react Building hotkeys in React apps

November 8, 2022

Listbox role state in React
react Listbox role state in React

January 29, 2021