React Keyboardist offers a simple and declarative way to add keyboard shortcuts to your react applications. It is just a React Wrapper for 🎹Keyboardist.
$ yarn add react-keyboardist
or
$ npm install --save react-keyboardist
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 keybvoard events inside an input using a similar API, React Keyboardist also comes with a KeyboardInput component.
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.
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,
}}
/>
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>
);
};
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
}}
/>
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.
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>
);
}
}
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} />
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.
If your application is some kind of Admin Dashboard, you may be using React-Router for the different sections of the app. React Router + Keyboardist offers a drop-in replacement for the Route
component that allows to assign a keyboard shortcut to every route.
Here's a blog post with the reasoning behind it.