react-hotkeys-hook Documentation

website·Indexed 29 days ago

https://react-hotkeys-hook.vercel.app/

A React hook for handling keyboard shortcuts in a declarative way. Includes documentation for the useHotkeys and useRecordHotkeys APIs, HotkeysProvider for scoping hotkeys, and the isHotkeyPressed utility.

Tokens
6.9K
Snippets
49
Records
52
Agent score
75%

What's inside react-hotkeys-hook

  1. Migrate useHotkeys options and context from v4 to v5

    Several options and context properties have been renamed in version 5 to improve clarity:

    useHotkeys Options:

    • combinationKey (v4) $\rightarrow$ splitKey (v5): Character that joins keys in a combination (default: +).
    • splitKey (v4) $\rightarrow$ delimiter (v5): Character that separates different hotkey combinations (default: ,).

    HotkeysProvider Context:

    • enabledScopes (v4) $\rightarrow$ activeScopes (v5).
    // v4
    useHotkeys('ctrl+a, shift+b', callback, { combinationKey: '-', splitKey: ';' })
    const { enabledScopes } = useHotkeysContext()
    
    // v5
    useHotkeys('ctrl+a, shift+b', callback, { splitKey: '-', delimiter: ';' })
    const { activeScopes } = useHotkeysContext()
  2. Enable hotkey scoping for non-focusable elements

    Elements like <div>, <section>, and <span> are not focusable by default. To scope a hotkey to these containers, add a tabIndex attribute. Using tabIndex={-1} allows the element to be focused via mouse click or JavaScript without adding it to the keyboard tab order, preserving the page's natural navigation flow.
    function ScopedHotkey() {
      const [count, setCount] = useState(0)
      const ref = useHotkeys('shift+a', () => setCount(prevCount => prevCount + 1))
    
      return (
        <div 
          ref={ref} 
          tabIndex={-1} 
          style={{border: '2px solid #9e768f', padding: '12px'}}
        >
          <p>The count is {count}. Click inside this area to enable the hotkey.</p>
        </div>
      )
    }
  3. Install and import useHotkeys

    The useHotkeys hook allows you to listen to keyboard shortcuts declaratively and execute a callback when the specified key combination is pressed. It automatically attaches the listener on component mount and removes it on unmount.
    import { useHotkeys } from 'react-hotkeys-hook';
    
    // Or using require
    const { useHotkeys } = require('react-hotkeys-hook');
  4. Bind hotkeys inside iframes

    When a React app is hosted inside an iframe, hotkeys must be bound to the iframe's document rather than the main page. Pass the iframe's document object in the options object.
    import FrameComponent from 'react-frame-component'
    
    function InsideFrameComponent() {
      const { document } = useFrame()
    
      useHotkeys('s', () => console.log('Triggered inside iframe'), { document })
    
      return <div>....</div>
    }
  5. Scope hotkeys to a specific element using the returned ref

    useHotkeys returns a React.RefCallback. When attached to an element, the hotkey will only trigger if that element (or one of its children) has focus.

    Note: Non-focusable elements (like div, span, or p) must have a tabIndex prop (e.g., tabIndex={0}) to be able to receive focus and trigger the hotkey.

    function App() {
      const [count, setCount] = useState(0);
      const ref = useHotkeys("s", () => setCount((prevCount) => prevCount + 1));
    
      return (
        <div>
          <div style={{ padding: "30px" }}>Count: {count}</div>
          {/* This div needs tabIndex to be focusable */}
          <div 
            style={{ padding: "30px", background: "crimson" }} 
            ref={ref} 
            tabIndex={0}
          >
            Focusing this area will trigger the hotkey.
          </div>
        </div>
      );
    }
  6. Migrate useHotkeys from v4 to v5 (Physical Keys vs Characters)

    In version 5, useHotkeys listens to physical key codes by default instead of produced characters. This means characters like ! will no longer trigger unless specified.

    Migration Options:

    1. Physical Keystroke (Layout-independent): Use the physical key combination (e.g., 'shift+1').
    2. Produced Character (Layout-dependent): Pass the useKey: true option to listen for the character (e.g., '!').
    // v5 Physical key (Recommended)
    useHotkeys('shift+1', callback);
    
    // v5 Character key (v4 behavior)
    useHotkeys('!', callback, { useKey: true });
  7. Handle keyboard shortcuts using physical key codes (layout-independent)

    By default, react-hotkeys-hook listens to the physical key code (KeyboardEvent.code). This ensures the shortcut triggers on the same physical key regardless of the user's keyboard layout. This is ideal for editor-style shortcuts where the physical position of the key is more important than the character it produces. Note that you should communicate the physical shortcut (e.g., 'shift+1') to users rather than the character (e.g., '!'), as the character may vary by layout.
    // Triggers when the physical keys for 'shift+1' are pressed
    useHotkeys('shift+1', () => setCount(prevCount => prevCount + 1))
    
    // Using physical key codes for symbols (case-insensitive)
    useHotkeys('Semicolon', () => handleSemicolon())
    useHotkeys('ctrl+Equal', zoomIn, { preventDefault: true })
    useHotkeys('ctrl+Minus', zoomOut, { preventDefault: true })
    useHotkeys('mod+Slash', toggleComment)
  8. Scope hotkeys to a specific component

    By default, useHotkeys attaches hotkeys globally. To limit a hotkey so it only triggers when a specific component or element is focused, use the React ref callback returned by the useHotkeys hook and attach it to the target element.
    function ScopedHotkey() {
      const [count, setCount] = useState(0)
      // useHotkeys returns a ref callback when a hotkey is defined
      const ref = useHotkeys('shift+a', () => setCount(prevCount => prevCount + 1))
    
      return (
        <>
          <p>The count is {count}.</p>
          {/* Attach the ref to the element that should trigger the hotkey when focused */}
          <button ref={ref}>
            Click me to enable the hotkey
          </button>
        </>
      )
    }
  9. Install react-hotkeys-hook

    Install the react-hotkeys-hook package using a package manager or via CDN. The library is written in TypeScript, so no separate @types package is required.
    # Using npm
    npm i react-hotkeys-hook
    
    # Using yarn
    yarn add react-hotkeys-hook
    
    # Using bun
    bun i react-hotkeys-hook
    // Via CDN (ES Module)
    import { useHotkeys } from 'https://unpkg.com/react-hotkeys-hook@latest/dist/react-hotkeys-hook.esm.js';
  10. Implement sequential hotkeys

    Use the > character to define a sequence of keys that must be pressed in order. By default, the user has 1 second between each key press before the sequence resets. This timeout can be customized using the sequenceTimeoutMs option.
    useHotkeys('g>h>i', () => console.log('Sequence triggered!'), {
      sequenceTimeoutMs: 10000, // Increase timeout to 10 seconds
    });
  11. Use TypeScript with react-hotkeys-hook

    The library is written in TypeScript and provides built-in types. You can type the ref returned by useHotkeys by passing the element type as a generic, and the options object is fully typed for autocomplete.
    import { useHotkeys } from "react-hotkeys-hook";
    
    const MyComponent = () => {
      // Typing the ref for a div element
      const ref = useHotkeys<HTMLDivElement>(
        'ctrl+s',
        () => console.log('Saved'),
        {
          enabled: true,
          scopes: ['editor'],
        }
      );
    
      return <div ref={ref} tabIndex={-1}>Content</div>;
    }