Migrating from Mousetrap or hotkeys-js
Both are solid, long-running libraries — this isn't "they're bad, switch." It's an API mapping for when you specifically want first-class TypeScript, scopes, a React hook, or SSR-safety without writing the glue yourself, plus the one thing that doesn't carry over cleanly either way.
From Mousetrap
| Mousetrap | bind-keyboard |
|---|---|
Mousetrap.bind('ctrl+a', fn) |
bindKeyboard.add('ctrl+a', fn) |
Mousetrap.unbind('ctrl+a') |
bindKeyboard.remove('ctrl+a') |
Mousetrap.bind('g i', fn) (sequence) |
bindKeyboard.add('g,i', fn) (comma, not space) |
Mousetrap.reset() |
bindKeyboard.removeAll() |
| no built-in scopes |
{ scope: 'modal' } + enableScope/disableScope
|
| no built-in React hook | useKeybind (bind-keyboard/react) |
The one-argument shorthand carries over almost verbatim; the biggest
real difference is the sequence separator (comma, not space) and that
type is an explicit argument rather than inferred.
From hotkeys-js
| hotkeys-js | bind-keyboard |
|---|---|
hotkeys('ctrl+a', fn) |
bindKeyboard.add('ctrl+a', fn) |
hotkeys.unbind('ctrl+a') |
bindKeyboard.remove('ctrl+a') |
hotkeys.setScope('modal') (one global scope) |
bindKeyboard.enableScope('modal') (several can be
active at once)
|
hotkeys.filter = (event) => ... |
checkInputElements + per-binding
allowInInputElements
|
| no temporal sequences |
bindKeyboard.add('g,i', fn) — see the
sequences recipe
|
The scope model is the real behavioral difference to know about: hotkeys-js has exactly one active scope at a time (switching to a new one deactivates the old), while bind-keyboard can have several scopes active simultaneously (each independently enabled/disabled), plus an always-on unscoped tier underneath all of them.
The one thing with no direct equivalent
hotkeys-js supports hotkeys('ctrl+a+s', fn) — a real
simultaneous chord of two non-modifier keys held together, via
its own tracked set of currently-held keys across separate
keydown/keyup events. bind-keyboard resolves
every combination from a single KeyboardEvent, which only
ever carries one non-modifier key at a time (plus its four modifier
flags) — so a string like "ctrl+a+s" throws a
KeybindError here instead of silently mismatching. If
you're migrating a binding like that, the closest equivalents are a
sequence (if pressing them one
after another is acceptable) or two separate bindings for whatever the
actual intent was.
Related
Vim and Gmail-style key sequences · React keyboard shortcuts: the useKeybind hook · Keyboard shortcuts inside a modal