React Shortcuts
Manage keyboard shortcuts from one place.travis
Intro
Managing keyboard shortcuts can sometimes get messy. Or always, if not implemented the right way.Real problems:
- You can't easily tell which shortcut is bound to which component
- You have to write a lot of boilerplate code (
addEventListeners
,removeEventListeners
, ...) - Memory leaks are a real problem if components don’t remove their listeners properly
- Platform specific shortcuts is another headache
- It's more difficult to implement feature like user-defined shortcuts
- You can't easily get allthe application shortcuts and display it (e.g. in settings)
React shortcuts to the rescue!
Withreact-shortcuts
you can declaratively manage shortcuts for each one of your React components.Important parts of React Shortcuts:
- Your
keymap
definition ShortcutManager
which handleskeymap
<Shortcut>
component for handling shortcuts
Try online demo
Quick tour
npm install react-shortcuts
npm install react-shortcuts
- Define application shortcuts
Create a new JS, Coffee, JSON or CSON file wherever you want (which probably is your project root). And define the shortcuts for your React component.Keymap definition
{
"Namespace": {
"Action": "Shortcut",
"Action_2": ["Shortcut", "Shortcut"],
"Action_3": {
"osx": "Shortcut",
"windows": ["Shortcut", "Shortcut"],
"linux": "Shortcut",
"other": "Shortcut"
}
}
}
Namespace
should ideally be the component’sdisplayName
.Action
describes what will be happening. For exampleMODAL_CLOSE
.Keyboard shortcut
can be a string, array of strings or an object which
a
, 6
,…), combinations
(command+shift+k
) or sequences (up up down down left right left right B A
).Combokeys is used under thehood for handling the shortcuts. Read moremousetrap about how you can specify keys.
Example keymap
definition:
export default {
TODO_ITEM: {
MOVE_LEFT: 'left',
MOVE_RIGHT: 'right',
MOVE_UP: ['up', 'w'],
DELETE: {
osx: ['command+backspace', 'k'],
windows: 'delete',
linux: 'delete',
},
},
}
Save this file as
keymap.[js|coffee|json|cson]
and require it into your main
file.import keymap from './keymap'
- Rise of the ShortcutsManager
Define your keymap in whichever supported format but in the end it must be an
object. ShortcutsManager
can’t parse JSON and will certainly not be happy
about the situation.import keymap from './keymap'
import { ShortcutManager } from 'react-shortcuts'
const shortcutManager = new ShortcutManager(keymap)
// Or like this
const shortcutManager = new ShortcutManager()
shortcutManager.setKeymap(keymap)
- Include
shortcutManager
into getChildContext of some parent component. So that <shortcuts>
can receive it.
shortcutManager
into getChildContext of some parent component. So that <shortcuts>
can receive it.class App extends React.Component {
getChildContext() {
return { shortcuts: shortcutManager }
}
}
App.childContextTypes = {
shortcuts: PropTypes.object.isRequired
}
- Require the component
You need to require the component in the file you want to use shortcuts in.
For example <TodoItem>
.import { Shortcuts } from `react-shortcuts`
class TodoItem extends React.Component {
_handleShortcuts = (action, event) => {
switch (action) {
case 'MOVE_LEFT':
console.log('moving left')
break
case 'MOVE_RIGHT':
console.log('moving right')
break
case 'MOVE_UP':
console.log('moving up')
break
case 'COPY':
console.log('copying stuff')
break
}
}
render() {
return (
<Shortcuts
name='TODO_ITEM'
handler={this._handleShortcuts}
>
<div>Make something amazing today</div>
</Shortcuts>
)
}
}
Thelisteners and adds tabIndex to the element so that it’s focusable.<Shortcuts>
component creates a<shortcuts>
element in HTML, binds
_handleShortcuts
is invoked when some of the defined shortcuts fire.Custom props for <Shortcuts>
component
handler
: func
name
: string
tabIndex
: number
-1
className
: stringeventType
: string
stopPropagation
: boolpreventDefault
: booltargetNodeSelector
: DOM Node Selector likebody
or.my-class
global
: bool
CMD+Q
.isolate
: bool
alwaysFireHandler
: bool