Skip to content
keymap logoKeymapApp Infrastructure
Chord-aware keyboard shortcut manager with context guards, modifier aliases, and disposable bindings — no DOM assumptions.
v1.1.02.5 KB gzip0 depsBrowser · Node.js · SSR · Deno
canonicalizeShortcutcreateKeymapcreateKeymapLayerdetectModKeyfindShortcutConflictsformatShortcutKeymapErrorKeymapParseError +3 more →

Why Keymap?

Browser keyboard handling is error-prone: modifier key normalisation, platform differences (ctrl vs meta), chord sequences, and cleanup all require boilerplate. Keymap handles all of it in a headless, zero-dependency package.

FeatureRaw addEventListenerKeymap
Bundle size0 B (built-in)2.5 KB
Zero dependencies
Chord sequences
Modifier aliasescmd, win, option → canonical
Context guardsManual if in handlerwhen() predicate per keymap
Headless / SSR-safeDOM required
DisposableManual removeEventListenerdispose() + using

Use Keymap when you need chord sequences (g g, ctrl+k ctrl+s), modifier aliases, or context-scoped hotkeys that can be cleanly mounted and unmounted.

Stick with raw addEventListener when you have a single, static, never-removed hotkey and don't need chords.

Installation

sh
pnpm add @vielzeug/keymap
sh
npm install @vielzeug/keymap
sh
yarn add @vielzeug/keymap

Quick Start

ts
import { createKeymap } from '@vielzeug/keymap';

const map = createKeymap({
  'ctrl+k ctrl+s': () => save(),
  'meta+shift+p':  () => openPalette(),
  'g g':           () => goToTop(),
  'escape':        () => closePanel(),
});

const unmount = map.mount(document);

// Later:
unmount();     // remove from this target only
map.dispose(); // or: using map = createKeymap(…)

Features

  • createKeymap() — Create a keymap from a bindings record; mount to any EventTarget
  • Chord sequences — "g g", "ctrl+k ctrl+s" with configurable timeout (default 1 s)
  • Modifier aliases — cmd/command/winmeta; opt/optionalt; mod → platform-aware
  • BindingOptions — per-binding { handler, when?, trigger?, priority? } object syntax
  • modKey option — explicit platform override for SSR and cross-platform tests
  • formatShortcut() — platform-aware display (⇧⌘P on Mac, Ctrl+Shift+P elsewhere)
  • createKeymapLayer() — scoped keymap stack with activate() / deactivate()
  • parseShortcut() / parseStep() / matchStep() — exposed for building custom matchers or testing
  • canonicalizeShortcut() — convert any shortcut alias to a stable key for conflict detection
  • detectModKey() — platform modifier detection ('meta' on Mac, 'ctrl' elsewhere)
  • listBindings() — snapshot all active bindings (shortcut, trigger, priority) for palette UIs
  • findShortcutConflicts() — detect prefix/duplicate conflicts before binding a user-customized shortcut
  • Disposable — dispose() + [Symbol.dispose] for using declarations

Documentation

See Also

  • Herald — Typed event bus; pair with Keymap by publishing shortcut events to a bus instead of calling handlers directly
  • Refineore-command-palette uses Keymap internally; register your own shortcuts alongside it
  • Ore — Attach a keymap inside a define() setup function for component-scoped shortcuts