Zero dependencies · TypeScript · ~3kB gzip

Keyboard shortcuts
your users will actually find

Register hotkeys, display a beautiful overlay with ?, handle sequences, groups, and modifiers — in 5 lines.

Or just press ? on your keyboard right now
Framework agnostic Sequence shortcuts Dark / Light / Auto SSR safe Accessible
Why hotkey-hint

Everything you need, nothing you don't

🎯

One-line registration

Register hotkeys with .register(). Supports modifiers, sequences, and groups out of the box.

Beautiful overlay

Press ? to reveal a polished shortcut sheet, grouped and labeled. Like GitHub, Figma, and Linear.

⌨️

Sequence shortcuts

Support for vim-style sequences like g then h. First-class citizen, not an afterthought.

🎨

Themes & auto

Dark, light, or auto (follows system preference). CSS variables let you fully customize the look.

🚫

Zero dependencies

No React, no Lodash, no moment.js. Just a clean TypeScript class you drop into any project.

📦

ESM + CJS + Types

Ships as ESM, CommonJS, and TypeScript types. Works everywhere: Vite, Next.js, webpack, CDN.

Interactive Demo

Try it right here

This page is wired up with hotkey-hint

Press ? anywhere to open the shortcut overlay, or try the shortcuts below

Get Started

Install in 30 seconds

npm install hotkey-hint
yarn add hotkey-hint
pnpm add hotkey-hint
<script type="module">
  import HotkeyHint from 'https://esm.sh/hotkey-hint';
</script>
import HotkeyHint from 'hotkey-hint';

const hh = new HotkeyHint({ theme: 'auto' });

hh.registerAll([
  {
    keys: 'ctrl+k',
    description: 'Open command palette',
    action: () => openCommandPalette(),
  },
  {
    keys: 'ctrl+s',
    description: 'Save document',
    action: () => save(),
  },
]);

// Press ? to open the overlay automatically
hh.registerAll([
  // Navigation group
  { keys: 'g then h', description: 'Go home',    group: 'Navigation', action },
  { keys: 'g then p', description: 'Go to profile', group: 'Navigation', action },

  // Editor group
  { keys: 'ctrl+b', description: 'Bold',    group: 'Editor', action },
  { keys: 'ctrl+i', description: 'Italic',  group: 'Editor', action },
  { keys: 'ctrl+u', description: 'Underline', group: 'Editor', action },
]);
// Vim-style sequences: press "g" then "h" within 2 seconds
hh.register({
  keys: 'g then h',
  description: 'Go to home',
  group: 'Navigation',
  action: () => router.push('/'),
});

hh.register({
  keys: 'g then s',
  description: 'Go to settings',
  group: 'Navigation',
  action: () => router.push('/settings'),
});
import { useEffect } from 'react';
import HotkeyHint from 'hotkey-hint';

function useHotkeys(hotkeys, deps = []) {
  useEffect(() => {
    const hh = new HotkeyHint({ theme: 'auto' });
    hh.registerAll(hotkeys);
    return () => hh.destroy(); // cleanup on unmount
  }, deps);
}

// In your component:
useHotkeys([
  { keys: 'ctrl+k', description: 'Search', action: openSearch },
  { keys: 'ctrl+/', description: 'Toggle sidebar', action: toggleSidebar },
]);
API Reference

Constructor options

Option Type Default Description
triggerKey string "?" Key that opens the overlay
theme "dark" | "light" | "auto" "auto" Color theme. Auto follows system preference
position "center" | "bottom-right" | "bottom-left" "center" Where the overlay panel appears
title string "Keyboard Shortcuts" Title shown at the top of the overlay
zIndex number 9999 CSS z-index for the overlay

Instance methods

Method Returns Description
.register(hotkey) this Register a single hotkey. Chainable.
.registerAll(hotkeys[]) this Register multiple hotkeys at once. Chainable.
.unregister(keys) this Remove a registered hotkey by its key string.
.show() void Programmatically show the overlay.
.hide() void Programmatically hide the overlay.
.toggle() void Show if hidden, hide if shown.
.destroy() void Remove all listeners and DOM elements. Call on unmount.