skills/vcode-sh/vibe-tools/tanstack-hotkeys-guide

tanstack-hotkeys-guide

SKILL.md

Purpose

TanStack Hotkeys is a type-safe, framework-agnostic library for handling keyboard shortcuts. It provides React hooks for registering hotkeys, multi-key sequences, recording custom shortcuts, tracking key state, and platform-aware display formatting. The library uses event.key as its primary API with event.code fallback for letter/digit keys. Currently in alpha -- API may change.

When NOT to use: For a single shortcut listener, a plain addEventListener('keydown', ...) may suffice. Reach for TanStack Hotkeys when you need multiple shortcuts, cross-platform Mod handling, sequences, recording, or key-state tracking.

Instructions

  • Always use Mod instead of platform-specific Meta or Control for cross-platform shortcuts
  • Import from @tanstack/react-hotkeys for React projects (it re-exports everything from @tanstack/hotkeys)
  • Import from @tanstack/hotkeys only for vanilla JS without React
  • Prefer the string form ('Mod+S') over RawHotkey objects unless the hotkey is dynamic or built programmatically
  • Always add tabIndex={0} to elements used as target refs -- they must be focusable to receive keyboard events
  • When building shortcut customization UIs, combine useHotkeyRecorder with formatForDisplay for recording and display
  • The recorder auto-converts platform keys to portable Mod format -- do not manually convert recorded hotkeys
  • Do NOT combine Mod with Control or Mod with Meta -- these create duplicate modifiers on one platform
  • Avoid Alt+letter shortcuts for cross-platform apps -- macOS produces special characters with Option+letter
  • Avoid Shift+number and Shift+punctuation shortcuts -- results are keyboard-layout-dependent
  • Warn the user that TanStack Hotkeys is in alpha when recommending it for production use
  • Default preventDefault: true and stopPropagation: true are intentional -- override explicitly only when needed
  • Use conflictBehavior: 'allow' for intentional duplicate hotkeys, not to silence bugs

Installation

npm install @tanstack/react-hotkeys

The React package re-exports everything from @tanstack/hotkeys. No separate core install needed. For vanilla JS only, install @tanstack/hotkeys directly.

Optional devtools:

npm install @tanstack/react-devtools @tanstack/react-hotkeys-devtools

Quick Start

import { useHotkey } from '@tanstack/react-hotkeys'

function App() {
  useHotkey('Mod+S', () => saveDocument())
  return <div>Press Cmd+S (Mac) or Ctrl+S (Windows) to save</div>
}

Mod resolves to Meta (Cmd) on macOS and Control on Windows/Linux.

React Hooks Reference

useHotkey(hotkey, callback, options?)

Register a keyboard shortcut. Auto-syncs callback every render (no stale closures). Auto-unregisters on unmount.

useHotkey('Mod+S', (event, { hotkey, parsedHotkey }) => {
  save()
})

Accept a string ('Mod+S') or RawHotkey object ({ key: 'S', mod: true }).

useHotkeySequence(sequence, callback, options?)

Register Vim-style multi-key sequences. Each step can include modifiers.

useHotkeySequence(['G', 'G'], () => scrollToTop())
useHotkeySequence(['Mod+K', 'Mod+C'], () => commentSelection())

Options: { timeout: 1000, enabled: true }.

useHotkeyRecorder(options)

Record custom keyboard shortcuts for settings UIs. Auto-converts to portable Mod format.

const { isRecording, recordedHotkey, startRecording, stopRecording, cancelRecording } =
  useHotkeyRecorder({ onRecord: (hotkey) => setShortcut(hotkey) })

Options: { onRecord, onCancel?, onClear? }. Escape cancels. Backspace/Delete clears.

useHeldKeys()

Return a reactive string[] of currently held key names.

useHeldKeyCodes()

Return a reactive Record<string, string> mapping key names to event.code values.

useKeyHold(key)

Return boolean for a specific key's hold state. Only re-renders when that key changes.

const isShiftHeld = useKeyHold('Shift')

useDefaultHotkeysOptions()

Return the current default options from HotkeysProvider context.

useHotkeysContext()

Return the full hotkeys context value, or null if outside a provider.

HotkeysProvider

Wrap the app to set global default options. Per-hook options override provider defaults.

import { HotkeysProvider } from '@tanstack/react-hotkeys'

<HotkeysProvider defaultOptions={{
  hotkey: { preventDefault: true },
  hotkeySequence: { timeout: 1500 },
  hotkeyRecorder: { onCancel: () => console.log('cancelled') },
}}>
  <App />
</HotkeysProvider>

Hotkey String Format

  • Modifiers: Control, Alt, Shift, Meta
  • Cross-platform: Mod (Cmd on Mac, Ctrl on Windows/Linux)
  • Format: Modifier+Modifier+Key -- e.g., 'Mod+Shift+S'
  • Single keys: 'Escape', 'Enter', 'F1', 'ArrowUp', 'A', '1', '/'
  • RawHotkey alternative: { key: 'S', mod: true, shift: true }
  • Mod+Control and Mod+Meta combinations are NOT allowed (would duplicate modifiers)

useHotkey Options

Option Default Description
enabled true Whether the hotkey is active
preventDefault true Call event.preventDefault()
stopPropagation true Call event.stopPropagation()
eventType 'keydown' 'keydown' or 'keyup'
requireReset false Fire only once per key press
ignoreInputs smart false for Mod+key and Escape; true for single keys and Shift/Alt combos
target document DOM element, document, window, or React ref
conflictBehavior 'warn' 'warn', 'error', 'replace', or 'allow'
platform auto Override: 'mac', 'windows', 'linux'

Smart ignoreInputs default: Mod+key shortcuts and Escape fire in text inputs. Single keys and Shift/Alt combos are ignored. Button-type inputs (type="button/submit/reset") are NOT ignored -- shortcuts work on them.

Display Formatting

import { formatForDisplay, formatWithLabels, formatKeyForDebuggingDisplay } from '@tanstack/react-hotkeys'

formatForDisplay('Mod+S')        // Mac: "⌘S"         Windows: "Ctrl+S"
formatWithLabels('Mod+S')        // Mac: "Cmd+S"      Windows: "Ctrl+S"
formatKeyForDebuggingDisplay('Meta') // Mac: "⌘ Mod (Cmd)"

Options: { platform: 'mac' | 'windows' | 'linux' }.

Core Utilities (Vanilla JS)

Use these without React:

import {
  parseHotkey, normalizeHotkey, validateHotkey,
  createHotkeyHandler, createMultiHotkeyHandler, createSequenceMatcher,
  getHotkeyManager, getKeyStateTracker, getSequenceManager,
} from '@tanstack/hotkeys'
  • parseHotkey('Mod+S') -- return ParsedHotkey object
  • normalizeHotkey('cmd+s') -- return canonical form 'Meta+S'
  • validateHotkey('Alt+A') -- return { valid, warnings, errors }
  • createHotkeyHandler('Mod+S', callback) -- return event handler function
  • createMultiHotkeyHandler({ 'Mod+S': save, 'Mod+Z': undo }) -- return single event handler
  • createSequenceMatcher(['G', 'G'], { timeout: 500 }) -- return { match(), reset(), getProgress() }

Key Rules and Gotchas

  • Library is in ALPHA -- API may change
  • Mod is the recommended way to write cross-platform shortcuts
  • Default preventDefault: true and stopPropagation: true -- override explicitly if needed
  • When using target with a ref, ensure the element has tabIndex for focus
  • macOS may swallow keyup events for non-modifier keys when a modifier is held -- library handles this
  • Window blur auto-clears all held keys to prevent "stuck" keys
  • conflictBehavior: 'warn' is default -- logs duplicates during development
  • event.key is primary. event.code is fallback for letter/digit keys when event.key produces special characters (macOS Option+letter, Shift+number)
  • Alt+letter on macOS may produce special characters. validateHotkey warns about this
  • Shift+number and Shift+punctuation produce layout-dependent characters (Shift+1 → !) -- avoid these combos; use Mod+number instead
  • SSR: detectPlatform() defaults to 'linux' when navigator is undefined -- Mod resolves to Control during server rendering
  • Canonical modifier order in normalized strings: Control → Alt → Shift → Meta

Devtools Setup

import { TanStackDevtools } from '@tanstack/react-devtools'
import { hotkeysDevtoolsPlugin } from '@tanstack/react-hotkeys-devtools'

function App() {
  return (
    <div>
      <TanStackDevtools plugins={[hotkeysDevtoolsPlugin()]} />
    </div>
  )
}

Devtools are no-op in production by default. Use /production import path for production debugging:

import { hotkeysDevtoolsPlugin } from '@tanstack/react-hotkeys-devtools/production'

Reference Files

  • references/api-reference.md -- Full API surface with types and interfaces. Read when you need exact type signatures, constructor parameters, or constant values.
  • references/patterns.md -- 25 usage patterns with complete code examples. Read when generating component code, building UIs with hotkeys, or choosing between implementation approaches.
  • references/troubleshooting.md -- Platform quirks, common issues, and solutions. Read when debugging hotkey issues, when the user reports unexpected behavior, or when working with macOS/SSR edge cases.
Weekly Installs
5
GitHub Stars
16
First Seen
Feb 24, 2026
Installed on
gemini-cli5
amp5
github-copilot5
codex5
kimi-cli5
opencode5