CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-react-hotkeys-hook

React hook for handling keyboard shortcuts in components in a declarative way

Pending
Overview
Eval results
Files

main-hook.mddocs/

Main Hotkey Hook

The primary hook for binding keyboard shortcuts to callback functions with extensive customization options including scopes, focus trapping, form element handling, and event lifecycle control.

Capabilities

useHotkeys Hook

The main hook for handling keyboard shortcuts in React components.

/**
 * Hook for binding keyboard shortcuts to callback functions
 * @param keys - Key or array of keys to listen for (e.g., 'ctrl+k', ['ctrl+k', 'cmd+k'])
 * @param callback - Function called when hotkey is triggered
 * @param options - Configuration options or dependency array
 * @param dependencies - Dependency array for callback memoization (if options is used for configuration)
 * @returns RefObject for optional focus trapping
 */
function useHotkeys<T extends HTMLElement>(
  keys: Keys,
  callback: HotkeyCallback,
  options?: OptionsOrDependencyArray,
  dependencies?: OptionsOrDependencyArray
): React.RefObject<T>;

type Keys = string | readonly string[];
type HotkeyCallback = (keyboardEvent: KeyboardEvent, hotkeysEvent: HotkeysEvent) => void;
type OptionsOrDependencyArray = Options | DependencyList;

Usage Examples:

import { useHotkeys } from 'react-hotkeys-hook';

// Basic usage with dependency array
const [count, setCount] = useState(0);
useHotkeys('ctrl+k', () => setCount(c => c + 1), [count]);

// Multiple key combinations
useHotkeys(['ctrl+k', 'cmd+k'], () => console.log('Works on both platforms'));

// With options object
useHotkeys('enter', handleSubmit, {
  enabled: isFormValid,
  enableOnFormTags: ['input', 'textarea'],
  preventDefault: true
});

// Focus trapping with ref
const ref = useHotkeys<HTMLDivElement>('escape', handleClose);
return <div ref={ref} tabIndex={-1}>Content</div>;

// Key sequences
useHotkeys('g>i', () => console.log('Vi-style sequence'), {
  sequenceTimeoutMs: 2000
});

Configuration Options

Options Interface

Complete configuration object for customizing hotkey behavior.

interface Options {
  /** Enable/disable hotkey conditionally (default: true) */
  enabled?: Trigger;
  /** Enable hotkeys on form tags (default: false) */
  enableOnFormTags?: readonly FormTags[] | boolean;
  /** Enable hotkeys on contentEditable elements (default: false) */
  enableOnContentEditable?: boolean;
  /** Ignore events based on condition (default: undefined) */
  ignoreEventWhen?: (e: KeyboardEvent) => boolean;
  /** Character to split keys in combinations (default: '+') */
  splitKey?: string;
  /** Character to separate different hotkeys (default: ',') */
  delimiter?: string;
  /** Scope restriction for hotkey (default: undefined) */
  scopes?: Scopes;
  /** Trigger on keyup event (default: undefined) */
  keyup?: boolean;
  /** Trigger on keydown event (default: true) */
  keydown?: boolean;
  /** Prevent default browser behavior (default: false) */
  preventDefault?: Trigger;
  /** Description for documentation (default: undefined) */
  description?: string;
  /** Custom document to listen on (default: false) */
  document?: Document;
  /** Ignore modifiers when matching (default: false) */
  ignoreModifiers?: boolean;
  /** Event listener options (default: undefined) */
  eventListenerOptions?: EventListenerOptions;
  /** Use key instead of code for matching (default: false) */
  useKey?: boolean;
  /** Timeout for key sequences (default: 1000ms) */
  sequenceTimeoutMs?: number;
  /** Character for key sequences (default: '>') */
  sequenceSplitKey?: string;
}

type Trigger = boolean | ((keyboardEvent: KeyboardEvent, hotkeysEvent: HotkeysEvent) => boolean);
type Scopes = string | readonly string[];
type FormTags = 'input' | 'textarea' | 'select' | 'INPUT' | 'TEXTAREA' | 'SELECT';

Configuration Examples:

// Conditional enabling
useHotkeys('ctrl+s', handleSave, {
  enabled: isDirty && !isSaving,
  preventDefault: true
});

// Function-based enabling
useHotkeys('delete', handleDelete, {
  enabled: (e, hotkey) => selectedItems.length > 0,
  preventDefault: (e, hotkey) => e.target.tagName !== 'INPUT'
});

// Form element handling
useHotkeys('enter', handleSubmit, {
  enableOnFormTags: ['input', 'textarea'],
  enableOnContentEditable: true
});

// Scope-based organization
useHotkeys('ctrl+n', createNew, {
  scopes: ['editor', 'global']
});

// Custom event options
useHotkeys('ctrl+z', handleUndo, {
  eventListenerOptions: { passive: false },
  keyup: true,
  keydown: false
});

Advanced Features

Key Sequences

Support for multi-key sequences like vi-style commands.

// Vi-style navigation
useHotkeys('g>g', () => scrollToTop(), {
  sequenceTimeoutMs: 1500,
  sequenceSplitKey: '>'
});

// Complex sequences
useHotkeys('ctrl+k>ctrl+c', () => openCommandPalette(), {
  description: 'Open command palette'
});

Focus Trapping

Limit hotkeys to specific elements using refs.

const modalRef = useHotkeys<HTMLDivElement>('escape', closeModal);

return (
  <div ref={modalRef} tabIndex={-1} className="modal">
    {/* Escape key only works when this element or its children are focused */}
  </div>
);

Event Lifecycle Control

Fine-grained control over when hotkeys trigger.

// Only on keyup
useHotkeys('space', handlePause, {
  keyup: true,
  keydown: false
});

// Both keyup and keydown
useHotkeys('shift', handleToggle, {
  keyup: true,
  keydown: true
});

Types

Callback and Event Types

type HotkeyCallback = (keyboardEvent: KeyboardEvent, hotkeysEvent: HotkeysEvent) => void;

interface HotkeysEvent extends KeyboardModifiers {
  keys?: readonly string[];
  scopes?: Scopes;
  description?: string;
  isSequence?: boolean;
}

interface KeyboardModifiers {
  alt?: boolean;
  ctrl?: boolean;
  meta?: boolean;
  shift?: boolean;
  mod?: boolean;
  useKey?: boolean;
}

Event Listener Options

type EventListenerOptions =
  | {
      capture?: boolean;
      once?: boolean;
      passive?: boolean;
      signal?: AbortSignal;
    }
  | boolean; // useCapture

Install with Tessl CLI

npx tessl i tessl/npm-react-hotkeys-hook

docs

index.md

key-checking.md

key-recording.md

main-hook.md

scope-management.md

tile.json