tinykeys vs hotkeys-js vs react-hotkeys-hook 2026
TL;DR
For new React apps, react-hotkeys-hook is the safest default. For tiny framework-agnostic bundles, tinykeys is the cleanest primitive. For large vanilla apps with multiple shortcut scopes, hotkeys-js still wins on built-in control.
Quick Comparison
| Library | npm package | Weekly downloads | Latest | Best for | Biggest tradeoff |
|---|---|---|---|---|---|
| tinykeys | tinykeys | ~145K/week | 3.0.0 | Small framework-agnostic apps, custom editors, and teams that want the smallest modern shortcut parser they can get. | No built-in scope system, so modal gating and app-level enable/disable logic are on you. |
| hotkeys-js | hotkeys-js | ~1.1M/week | 4.0.3 | Vanilla JavaScript apps, admin dashboards with multiple contexts, and mixed stacks that need a mature scoping model. | Global state and imperative scoping can feel awkward inside multi-root React apps or SSR-heavy codebases. |
| react-hotkeys-hook | react-hotkeys-hook | ~2.6M/week | 5.2.4 | React products with modals, command palettes, or panel-level shortcuts that need cleanup and ref scoping to feel automatic. | You pay for React abstraction and still need to think about dependency arrays and stale closures. |
Why this comparison matters in 2026
Keyboard shortcuts are a tiny detail until they break command menus, editor-style UIs, or power-user workflows. The real decision is not just API preference; it is whether you need a zero-dependency vanilla binding layer, a mature scope system, or a React-first hook that behaves well with refs and component state.
In 2026, more React apps ship command menus, editor surfaces, and multi-panel productivity UI by default. That makes keyboard handling a first-class product concern instead of a nice-to-have enhancement. The difference between global bindings, scoped bindings, and form-safe bindings shows up immediately in production.
This topic is intentionally adjacent to existing PkgPulse coverage, not a duplicate. Existing coverage touches cmdk inside a select/combobox article. This version stays focused on keyboard shortcut bindings, scopes, and React integration.
What actually changes the decision
- Scope control matters more than syntax. A global shortcut is fine for a marketing site, but dashboard apps need modal-level and panel-level control.
- React cleanup matters. Libraries that make rebinding or ref scoping awkward tend to create stale closures, double bindings, or shortcuts that fire from closed overlays.
- Bundle size is real here because all three libraries solve a narrow problem. If you only need half a dozen bindings, the lightest tool often wins.
tinykeys
Package: tinykeys | Weekly downloads: ~145K | Latest: 3.0.0
tinykeys is the best fit when you want a tiny primitive and are comfortable building the rest of the interaction model yourself. It feels modern because the API is intentionally narrow: parse key strings, register listeners, clean up cleanly.
import { createKeybindingsHandler } from 'tinykeys';
const unsubscribe = createKeybindingsHandler({
'$mod+k': (event) => {
event.preventDefault();
openCommandPalette();
},
'g i': () => navigate('/inbox'),
});
document.addEventListener('keydown', unsubscribe);
Best for: Small framework-agnostic apps, custom editors, and teams that want the smallest modern shortcut parser they can get. Tradeoff: No built-in scope system, so modal gating and app-level enable/disable logic are on you.
Strengths:
- Extremely small bundle footprint
- Modern
$modsyntax and good support for sequences/chords - Framework-agnostic and easy to wrap in your own hook or service
Watch-outs:
- You build your own scoping model
- No React-specific ergonomics out of the box
hotkeys-js
Package: hotkeys-js | Weekly downloads: ~1.1M | Latest: 4.0.3
hotkeys-js still earns its place because scope management is not an afterthought. If your app has global shortcuts, modal shortcuts, and nested editing surfaces, that built-in model is a real operational advantage.
import hotkeys from 'hotkeys-js';
hotkeys('ctrl+k, command+k', 'dashboard', (event) => {
event.preventDefault();
openPalette();
});
hotkeys.setScope('dashboard');
Best for: Vanilla JavaScript apps, admin dashboards with multiple contexts, and mixed stacks that need a mature scoping model. Tradeoff: Global state and imperative scoping can feel awkward inside multi-root React apps or SSR-heavy codebases.
Strengths:
- Battle-tested API and extensive real-world examples
- Built-in scopes and filter hooks
- Works well outside React, including legacy DOM-heavy apps
Watch-outs:
- Less idiomatic in component-driven UI frameworks
- More surface area than most apps actually need
react-hotkeys-hook
Package: react-hotkeys-hook | Weekly downloads: ~2.6M | Latest: 5.2.4
react-hotkeys-hook is usually the fastest route to a polished React result. It maps keyboard bindings to the component tree instead of forcing you to maintain a separate imperative registry.
import { useHotkeys } from 'react-hotkeys-hook';
export function SearchButton() {
useHotkeys('meta+k, ctrl+k', (event) => {
event.preventDefault();
openPalette();
}, { enableOnFormTags: false });
return <button onClick={openPalette}>Search</button>;
}
Best for: React products with modals, command palettes, or panel-level shortcuts that need cleanup and ref scoping to feel automatic. Tradeoff: You pay for React abstraction and still need to think about dependency arrays and stale closures.
Strengths:
- Idiomatic hook API
- Automatic lifecycle cleanup
- Ref scoping and form-input controls
Watch-outs:
- React-only
- Can rebind too often if hooks are wired carelessly
Which one should you choose?
- Choose tinykeys when small framework-agnostic apps, custom editors, and teams that want the smallest modern shortcut parser they can get.
- Choose hotkeys-js when vanilla JavaScript apps, admin dashboards with multiple contexts, and mixed stacks that need a mature scoping model.
- Choose react-hotkeys-hook when react products with modals, command palettes, or panel-level shortcuts that need cleanup and ref scoping to feel automatic.
Final recommendation
For new React apps, react-hotkeys-hook is the safest default. For tiny framework-agnostic bundles, tinykeys is the cleanest primitive. For large vanilla apps with multiple shortcut scopes, hotkeys-js still wins on built-in control.
Related reading
react-select vs cmdk vs Downshift 2026 · Best React Hook Libraries 2026