I built a tiny, zero-dependency React hook for keyboard shortcuts

Most apps eventually need keyboard shortcuts – a command palette on Cmd/Ctrl+K, Esc to close a modal, mod+S to save. I kept rewriting the same keydown boilerplate, so I packaged it into a tiny hook.

@dhruvilshah191999/use-shortcut – zero dependencies,…


This content originally appeared on DEV Community and was authored by Dhruvil Shah

Most apps eventually need keyboard shortcuts - a command palette on Cmd/Ctrl+K, Esc to close a modal, mod+S to save. I kept rewriting the same keydown boilerplate, so I packaged it into a tiny hook.

@dhruvilshah191999/use-shortcut - zero dependencies, ~1KB gzipped, TypeScript-first.

🔗 Live demo: https://use-shortcut-playground.vercel.app/

📦 npm: https://www.npmjs.com/package/@dhruvilshah191999/use-shortcut
💻 Source: https://github.com/dhruvilshah191999/use-shortcut

Install

npm install @dhruvilshah191999/use-shortcut

The basics

import { useShortcut } from "@dhruvilshah191999/use-shortcut";

function SearchButton() {
  const [open, setOpen] = useState(false);

  useShortcut("mod+k", () => setOpen(true));
  // ...
}

That's the whole API for simple cases: a combo string, a callback, done.

What makes it nice to use

mod is cross-platform out of the box

useShortcut("mod+s", save, { preventDefault: true }); // ⌘S on Mac, Ctrl+S elsewhere

Combos are case-insensitive and whitespace-tolerant ("Cmd+K", "cmd+k", " cmd + k " all work), with aliases like cmd↔command, ctrl↔control, alt↔option.

Smart input handling

By default, shortcuts don't fire while you're typing in an <input>, <textarea>, <select>, or contenteditable - except Escape, which always fires (closing a modal should work even with focus in a field). You can opt back in with enableInInputs: true.

Always-fresh callback (no useCallback needed)

The hook always calls the latest callback via a ref, so you never get a stale closure:

function Counter() {
  const [count, setCount] = useState(0);
  // logs the CURRENT count every time, no useCallback required
  useShortcut("c", () => console.log(count));
  return <button onClick={() => setCount((c) => c + 1)}>{count}</button>;
}

Optional scopes (when you outgrow "global")

Every shortcut is global by default. When you need the same key to mean different things in different parts of the UI, wrap a subtree in a provider and gate shortcuts by scope:

import {
  ShortcutProvider,
  useShortcut,
  useShortcutScopes,
} from "@dhruvilshah191999/use-shortcut";

function App() {
  return (
    <ShortcutProvider initialScopes={["list"]}>
      <List />
      <Modal />
    </ShortcutProvider>
  );
}

function Modal() {
  const { activate, deactivate } = useShortcutScopes();
  useShortcut("escape", close, { scope: "modal" }); // fires only when "modal" is active
  // open(): activate("modal"); deactivate("list");
}

Scopes are fully opt-in - if you never use a scope, nothing changes and you don't need the provider.

The whole API

useShortcut(
  key: string | string[],
  callback: (e: KeyboardEvent) => void,
  options?: {
    enabled?: boolean;          // default: true
    preventDefault?: boolean;   // default: false
    stopPropagation?: boolean;  // default: false
    enableInInputs?: boolean;   // default: false
    target?: RefObject<HTMLElement> | Window; // default: window
    scope?: string | string[];  // optional, opt-in
  }
): void

Try it

The live demo exercises every feature with an on-screen event log — open it and start pressing keys.

If you find it useful, a ⭐ on the repo is appreciated. Feedback and issues welcome!


This content originally appeared on DEV Community and was authored by Dhruvil Shah


Print Share Comment Cite Upload Translate Updates
APA

Dhruvil Shah | Sciencx (2026-06-07T07:23:21+00:00) I built a tiny, zero-dependency React hook for keyboard shortcuts. Retrieved from https://www.scien.cx/2026/06/07/i-built-a-tiny-zero-dependency-react-hook-for-keyboard-shortcuts/

MLA
" » I built a tiny, zero-dependency React hook for keyboard shortcuts." Dhruvil Shah | Sciencx - Sunday June 7, 2026, https://www.scien.cx/2026/06/07/i-built-a-tiny-zero-dependency-react-hook-for-keyboard-shortcuts/
HARVARD
Dhruvil Shah | Sciencx Sunday June 7, 2026 » I built a tiny, zero-dependency React hook for keyboard shortcuts., viewed ,<https://www.scien.cx/2026/06/07/i-built-a-tiny-zero-dependency-react-hook-for-keyboard-shortcuts/>
VANCOUVER
Dhruvil Shah | Sciencx - » I built a tiny, zero-dependency React hook for keyboard shortcuts. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2026/06/07/i-built-a-tiny-zero-dependency-react-hook-for-keyboard-shortcuts/
CHICAGO
" » I built a tiny, zero-dependency React hook for keyboard shortcuts." Dhruvil Shah | Sciencx - Accessed . https://www.scien.cx/2026/06/07/i-built-a-tiny-zero-dependency-react-hook-for-keyboard-shortcuts/
IEEE
" » I built a tiny, zero-dependency React hook for keyboard shortcuts." Dhruvil Shah | Sciencx [Online]. Available: https://www.scien.cx/2026/06/07/i-built-a-tiny-zero-dependency-react-hook-for-keyboard-shortcuts/. [Accessed: ]
rf:citation
» I built a tiny, zero-dependency React hook for keyboard shortcuts | Dhruvil Shah | Sciencx | https://www.scien.cx/2026/06/07/i-built-a-tiny-zero-dependency-react-hook-for-keyboard-shortcuts/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.