# react-hotkeys-hook: Declarative Keyboard Shortcuts for React Components

> react-hotkeys-hook attaches keyboard shortcuts to a component with a single useHotkeys call, and its scope system decides which shortcuts win. Here is how the hook works, how to install it, and where it stops being enough.

**JohannesKlauss/react-hotkeys-hook** — React hook for using keyboard shortcuts in components.

- Repository: https://github.com/JohannesKlauss/react-hotkeys-hook
- Website: https://react-hotkeys-hook.vercel.app/
- Stars: 3,506 · Forks: 168
- Language: TypeScript
- License: MIT
- Published: 2026-09-23 · Updated: 2026-09-23 · Language: en
- Canonical page: https://hysenlabs.com/projects/johannesklauss-react-hotkeys-hook

## What react-hotkeys-hook solves, and who it is for

Keyboard shortcuts in a React app usually start as a document-level listener in a useEffect. That works until two components both want ctrl+k, or until a shortcut should fire only while a panel is focused. react-hotkeys-hook moves the binding into the component that owns the behaviour. The README describes it as "A React hook for using keyboard shortcuts in components in a declarative way", and the API reflects that: useHotkeys takes the keys, a callback and an options object, and the hook handles registration and cleanup with the component lifecycle. The audience is React application developers building editors, dashboards, command palettes or any UI where power users expect shortcuts. It is a client-side library. Nothing in the README suggests server rendering of the hook itself, so it belongs in interactive components. The package is TypeScript-first, ships types through the types field in package.json, and is published under the MIT licence.

## How useHotkeys registers keys and what the callback receives

The signature documented in the README is useHotkeys(keys, callback, options, deps). keys accepts a string or an array of strings. Multiple keys are separated with a comma, and that separator can be changed through the splitKey option, which matters if a comma is part of a key combination you need. The callback receives two arguments: the browser's native KeyboardEvent and the library's own HotkeysEvent, so you can call preventDefault on the native event or read parsed information from the handler object. The fourth parameter is a DependencyList, which lets you control when the hook re-registers instead of relying on referential equality of the callback. Options also carry a scopes array. Registration is not global by default in the sense of being unconditional: when you pass scopes, the hook only fires while one of those scopes is active, and the HotkeysProvider tracks which scopes are currently on. disableScope, enableScope and toggleScope from useHotkeysContext change that state at runtime. The README notes that useHotkeysContext requires the app to be wrapped in HotkeysProvider, which is the constraint that makes scope switching possible.

## Installing react-hotkeys-hook and binding a first shortcut

The README gives a single install command. Run it in your project root; it adds react-hotkeys-hook to your dependencies. React and react-dom are peer dependencies with a minimum of 16.8.0, the version that introduced hooks, so any project on that range or newer is compatible.

```bash
npm i react-hotkeys-hook
```

Once installed, the quick start imports the hook and binds a combination to a callback. This example from the README increments a counter on ctrl+k:

```jsx
import { useHotkeys } from 'react-hotkeys-hook'

export const ExampleComponent = () => {
  const [count, setCount] = useState(0)
  useHotkeys('ctrl+k', () => setCount(prevCount => prevCount + 1))

  return (
    <p>
      Pressed {count} times.
    </p>
  )
}
```

After mounting the component, pressing ctrl+k should increase the displayed count by one on each press.

## Scopes, focus traps and the collision problem

Two components binding ctrl+k is the failure case this library is designed around. Scopes are the answer. You declare which scopes start active on the provider, tag each hook with the scopes it belongs to, and the hook stays inert while none of its scopes are active. The README's example wraps the app in HotkeysProvider with initiallyActiveScopes set to ['settings'] and registers the hook with { scopes: ['settings'] }. Switching at runtime goes through useHotkeysContext, which returns toggleScope among others. The second mechanism is the focus trap. useHotkeys returns a ref, and attaching that ref to an element with tabIndex={-1} means the shortcut fires only while that element is focused. That is the right tool for a shortcut that should apply inside one panel and not across the whole page. Both mechanisms are opt-in. If you pass neither scopes nor a ref, the hook behaves as a plain global binding, which is convenient and also how accidental collisions happen when a codebase grows.

## Where react-hotkeys-hook is the wrong tool

The library is React-only by construction. A shortcut that must work in a non-React part of the page, in a browser extension content script, or in a plain JavaScript widget cannot use the hook, because there is no component to attach it to. The second limit is scope of the key syntax. The README documents single keys, modifier combinations and comma-separated alternatives, plus a splitKey override. It does not document multi-stroke sequences such as g then i, which editors and Vim-style interfaces rely on. If you need chorded sequences, this hook is not the layer for it. Third, the README does not document rollback or migration behaviour between major versions, and the changelog is where that information would live rather than the README. Treat version upgrades as something to read up on, not something the README will tell you. Finally, because the callback receives the native event, anything you want to suppress, such as the browser's own ctrl+k handling, is your responsibility inside the callback.

## react-hotkeys-hook compared with a global keymap library

The closest alternative in the search data is hotkeys-js, a framework-agnostic keyboard shortcut library. The difference is architectural rather than cosmetic. hotkeys-js binds to the document and manages a global registry of shortcuts, so it works in any JavaScript context and does not care about your component tree. react-hotkeys-hook inverts that: the binding lives with the component, and the provider plus scopes decide which binding is live. The trade-off follows directly. A global registry is easier to reason about when shortcuts are application-wide and few, and it works outside React. A component-scoped hook is easier to reason about when shortcuts belong to features that mount and unmount, because cleanup happens with the component and you do not have to unregister by hand. If your app is React and your shortcuts map to components, the hook model removes a class of bugs. If your shortcuts are global and your app is not entirely React, the global registry is the simpler fit. Neither approach gives you multi-stroke sequences by default.

## Maintenance, licence and upgrade cost

The repository is not archived, and the last push was on 2026-09-21. Recent releases are v5.3.1 (2026-05-05), v5.3.2 (2026-05-05) and v5.3.3 (2026-06-26). The version strings in the release list are inconsistent, with one written as v.5.3.2, which is worth noting when you pin a version in package.json. Tooling is Biome for formatting and linting, and the publish script runs test, lint and build before publishing, so the published artifact is gated on those steps in the repository's own scripts. The package is MIT licensed, which permits commercial and closed-source use, but this is a description of the licence identifier and not legal advice about your situation. Upgrade cost is mostly the peer range: react and react-dom must be at least 16.8.0. The README does not document breaking changes between majors, so read CHANGELOG.md before moving across a major version rather than assuming the hook signature is stable.

## Conclusion

Adopt react-hotkeys-hook when shortcuts belong to components and you want scopes, focus traps and a HotkeysProvider to arbitrate collisions instead of a global listener registry. Skip it if your shortcuts must work outside React or you need a keymap engine with multi-stroke sequences, since the README documents single and comma-separated key combinations, not chords. Before committing, verify the peer range react >=16.8.0 against your React version, confirm your key combos against the documented API rather than guessing, and check the changelog for the 5.3.x releases before pinning a version.

## FAQ

### How do I install react-hotkeys-hook?

The README gives one command, npm i react-hotkeys-hook. React and react-dom are peer dependencies with a minimum version of 16.8.0.

### How do I stop two react-hotkeys-hook shortcuts from colliding?

Use scopes. Wrap the app in HotkeysProvider with initiallyActiveScopes, pass a scopes array in the hook options, and switch the active scope at runtime with toggleScope from useHotkeysContext.

### How do I make a react-hotkeys-hook shortcut fire only when an element is focused?

useHotkeys returns a ref. Attach that ref to an element with tabIndex={-1}, and the hotkey only triggers while the component is focused.

### Can react-hotkeys-hook be used outside React?

No. The library is a React hook and binds shortcuts inside components, so a non-React script or widget has no component to attach it to.

## Sources

- [JohannesKlauss/react-hotkeys-hook on GitHub](https://github.com/JohannesKlauss/react-hotkeys-hook)
- [License: MIT](https://github.com/JohannesKlauss/react-hotkeys-hook/blob/main/LICENSE)
- [Project website](https://react-hotkeys-hook.vercel.app/)
- [README](https://github.com/JohannesKlauss/react-hotkeys-hook/blob/main/README.md)
- [Releases](https://github.com/JohannesKlauss/react-hotkeys-hook/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/johannesklauss-react-hotkeys-hook
