/ Keyboard

An easy and declarative way to add keyboard shortcuts to your React app

An easy and declarative way to add keyboard shortcuts to your React app

React Keyboardist

React Keyboardist offers a simple and declarative way to add keyboard shortcuts to your react applications. It is just a React Wrapper for musical_keyboardKeyboardist.

Installation

$ yarn add react-keyboardist

or

$ npm install --save react-keyboardist

Global Listener

The default export <Keyboardist/> provides a global listener attached to the document element that will listen for every key event except those that happen inside input elements (e.g. <input/>,<textarea/>). This is useful, for example, to have keystrokes that activate different parts of your UI.

If you need to listen for keyboard events inside an input using a similar API, React Keyboardist also comes with a KeyboardInput component.

How to use

Just pass a dictionary with the shape of {keyName : [function]} via the bindings property and they will be automatically binded when the component mounts.

import Keyboardist from 'react-keyboardist';

class App extends React.Component {
  //... state methods would go here

  render() {
    return (
      <React.Fragment>
        <Keyboardist
          bindings={{
            Slash: this.focusSearch,
            Period: this.showMenu,
            Escape: this.logOut,
            KeyK: this.next,
            KeyJ: this.prev,
          }}
        />
        <RestOfTheApp />
      </React.Fragment>
    );
  }
}

All the subscription objects will be automatically unsuscribed when the component unmounts so you can use it as any other component in your component hierarchy.

Other Events

By default React Keyboardist will listen to keydown events, but you can use keyup instead.

<Keyboardist
  eventName="keyup"
  bindings={{
    Slash: this.focusSearch,
    Period: this.showMenu,
    Escape: this.logOut,
    KeyK: this.next,
    KeyJ: this.prev,
  }}
/>

Multiple listeners for a Key

You can add multiple listeners for the same key, and they will be executed
starting from the last one. If one of the listeners returns false the execution chain will stop. This is useful when you want to override a key in a child component.

const App = ({ openDialog, closeDialog, isDialogOpen, handleLogout }) => (
  <div>
    <Keyboardist
      bindings={{
        Enter: openDialog,
        Escape: handleLogout,
      }}
    />
    {isDialogOpen && <ModalDialog onClose={closeDialog} />}
  </div>
);

const ModalDialog = ({ onClose }) => {
  const bindings = {
    Escape: () => {
      onClose();
      // this will prevent the Escape binding in the parent component to be triggered.
      return false;
    },
  };
  return (
    <div className="dialog">
      <Keyboard bindings={bindings} />
      <DialogContentOrWhatever />
    </div>
  );
};

Event Monitor

The monitor property allows you to either pass a monitor function or just set it to true to use Keyboardist's default monitor. You can read more about Keyboardist monitor over here.

<Keyboardist
  bindings={bindings}
  monitor={(keyName, matched) => {
    // do something
  }}
/>

KeyboardInput

Sometimes you want to listen to key events inside an input or textarea element, for example, to make a keyboard-enabled live search or to add keyboard functions inside an editor.

How to use

KeyboardInput has pretty much the same API as the global listener, except that instead of not rendering anything, it will render either an <input/> component (by default) or a <textarea/> component.

The properties for KeyboardInput are bindings, eventName, monitor and component, every other property will be forwarded to the rendered component.

import { KeyboardInput } from 'react-keyboardist';

class App extends React.Component {
  //... state methods would go here

  render() {
    return (
      <React.Fragment>
        <KeyboardInput
          className={'tag-selector'}
          onFocus={this.showOptions}
          bindings={{
            Up: this.prevOption,
            Down: this.nextOption,
            Space: this.selectOption,
          }}
        />
        <RestOfTheApp />
      </React.Fragment>
    );
  }
}

Textarea

If you want the component to render a textarea element instead of an input, you can use the component property.

<Keyboardist component={'textarea'} bindings={bindings} />

Examples

If you want to see all the capabilites of React Keyboardist, here's a really contrived demo and you can find the source for that in the docs folder.

GitHub