Secrets of Gutenberg: The keyboard shortcuts package

If you’ve been following my blog or WordPress development for some time now, you’d know by now that the Gutenberg project contains a number of hidden gems that you, as a JavaScript developer or a WordPress developer can benefit from in your own standalone applications or WordPress plugins.

One of these hidden gems is the keyboard shortcuts package, a utility package that allows you to do all sort of things related to keyboard shortcuts, between adding keyboard shortcuts, removing keyboard shortcuts, updating them and more.

As a standalone package.

Like any package in the gutenberg package, it’s distributed as a standalone npm package that you can consume and use in any React application. Here’s a basic example (Full example available on Stackblitz):

import { ShortcutProvider, useShortcut, store } from '@wordpress/keyboard-shortcuts';
import { useState, useEffect } from '@wordpress/element';
import { useDispatch } from '@wordpress/data';

function MyCounter() {
  const [ count, setCount ] = useState( 0 );
  const { registerShortcut } = useDispatch( store );

  useEffect( () => {
    registerShortcut( {
      name: 'mycounter/increment',
      description: 'Increment the counter',
      keyCombination: {
        character: 'i'
      } 
    } );
  }, [] );

  useShortcut( 'mycounter/increment', () => {
    setCount( count + 1 );
  } );

  return (
    <div>
      Count: { count }
    </div>
  );
}

function App() {
  return (
    <ShortcutProvider>
      <MyCounter />
    </ShortcutProvider>
  );
}

So to use the package, first, you need to wrap your React application in a ShortcutProvider. (The shortcuts will only work if the active element is inside the shortcut provider in the DOM tree)

The next step is to register your shortcuts using the registerShortcut action. This function call declares the existence of your shortcut in your shortcuts store, providing the keyboard combination used to trigger the shortcut behavior and some additional metadata, like a description and a category.

It’s a good practice to register all your shortcuts when initially rendering your application component.

That said, for the shortcuts to actually perform any action, we need to define their callbacks, and we do so using the useShortcut react hook, the first argument being the shortcut name and the second the function that is called when the key combination is pressed.

Note: The reason registering shortcuts and using shortcuts are separate is because some shortcuts are contextual to specific actions but the application always need to know about the existence of a shortcut during its lifecycle. For instance, all shortcuts can be rendered in a help panel but all the shortcuts might not be active. For example, a “copy” shortcut in an editor is only active if there’s a selection.

The keyboard shortcuts package allows using single character shortcuts or shortcuts with one or two modifiers. These are all examples of valid key combinations:

  • { character: 'a' } is equivalent to pressing a.
  • { character: 'del' } is equivalent to pressing the delete button.
  • { character: 'a', modifier: 'primary' } is equivalent to pressing command + a on Mac.
  • { character: 'a', modifier: 'primaryShift' } is equivalent to pressing command + shift + a on Mac.
  • { character: 'a', modifier: 'alt' } is equivalent to pressing option + a on Mac.

As a WordPress API

In WordPress, the keyboard shortcuts package is used to register all the block editor shortcuts, but you can also use it to register your own custom shortcuts in your block or any WordPress plugin or page using the same API. It is available in the wp-keyboard-shorctuts wordpress script. If you plan on using it, in your plugin’s scripts, make sure to add the wp-keyboard-shorctuts as a dependency to your custom scripts:

function my_enqueue_scripts()
{
    wp_register_script( 'my_plugin_script', 'path-to-my-script.js', array( 'wp-keyboard-shortcuts' );
    wp_enqueue_script( 'my_plugin_script' );
}
add_action( 'wp_enqueue_scripts', 'my_enqueue_scripts' );

The wp.keyboardShortcuts global variable will be made available for you with all the APIs exposed by the package: useShortcut, ShortcutsProvider…

Super Powers

Editing keyboard shortcuts

An important aspect of implementing keyboard shortcuts in any application is to define the right key combinations for the right shortcut. That said, it is surprisingly hard to come up with combinations that work for everyone, in all browsers and all operating systems. For that reason, the keyboard shortcuts package allows the possibility to update the registered shortcuts and change their keyboard combination.

import { useSelect, useDispatch } from '@wordpress/data';
import { store } from '@wordpress/keyboard-shortcuts';

function ToggleIncrementShortcut() {
  const { getShortcutKeyCombination } = useSelect( store );
  const { registerShortcut } = useDispatch( store );

  const toggleShortcut = () => {
    const currentCharacter = getShortcutKeyCombination( 'mycounter/increment' )?.character;
    const nextCharacter = currentCharacter === 'a' ? 'i' : 'a';
    registerShortcut( {
      name: 'mycounter/increment',
      description: 'Increment the counter',
      keyCombination: {
        character: nextCharacter
      } 
    } );
  }

  return (
    <button onClick={ toggleShortcut }>
      Toggle between "i" and "a"
    </button>
  );
}

So as we can see in the example above, registering the shortcut again, overrides its current definition allowing us to update any of its properties including the key combination.

💡 In the future, the block editor might provide this automatically but until then, there’s an opportunity here for a WordPress plugin that provides a UI to edit the existing shortcuts.


Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: