npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@rocketc/react-use-shortcuts

v0.0.1

Published

a full react shortcut solution

Downloads

63

Readme

@rocketc/react-use-shortcuts


Full React shortcut solution built on top of @rocketc/shortcuts.

Features

  • React Hooks: Use useShortcut hook to access shortcut APIs
  • Context Provider: ReactShortcutProvider for React context integration
  • Strict/Loose mode: Support both strict and loose matching modes
  • Page scoped register: Register shortcuts scoped to specific elements
  • Dynamic register: Register and unregister shortcuts at runtime
  • Dynamic enable/disable: Enable or disable registered shortcuts dynamically
  • Flexible key combinations: Support complex modifier and normal key combinations
  • Use modern browser API: Uses modern browser APIs (KeyboardEvent.code)
  • Full TypeScript support: Complete type definitions included
  • Shortcut validation: Built-in validation for accelerator strings

Installation

# npm
npm install @rocketc/react-use-shortcuts

# yarn
yarn add @rocketc/react-use-shortcuts

# pnpm
pnpm add @rocketc/react-use-shortcuts

Note: This package depends on @rocketc/shortcuts for core functionality. It will be installed automatically.

Supported Keys

See the Supported Keys section in @rocketc/shortcuts documentation.

Quick Start

import React, { useEffect } from 'react';
import {
  ReactShortcutProvider,
  useShortcut,
} from '@rocketc/react-use-shortcuts';

function App() {
  return (
    <ReactShortcutProvider>
      <Main />
    </ReactShortcutProvider>
  );
}

function Main() {
  const { registerShortcut, unregisterShortcut } = useShortcut();

  useEffect(() => {
    registerShortcut('Ctrl+a', (event) => {
      console.log('Ctrl+A pressed!');
      event.preventDefault();
    });

    return () => {
      unregisterShortcut('Ctrl+a');
    };
  }, []);

  return <h1>Hello World!</h1>;
}

Examples

1. Register Single Key Shortcut

import React, { useEffect } from 'react';
import {
  ReactShortcutProvider,
  useShortcut,
} from '@rocketc/react-use-shortcuts';

function App() {
  return (
    <ReactShortcutProvider>
      <Main />
    </ReactShortcutProvider>
  );
}

function Main() {
  const { registerShortcut, unregisterShortcut } = useShortcut();

  useEffect(() => {
    registerShortcut('a', (event) => {
      event.preventDefault();
      console.log('You pressed A');
    });
    return () => {
      unregisterShortcut('a');
    };
  }, []);

  return <h1>Hello World!</h1>;
}

2. Register Shortcut with Modifiers

import React, { useEffect } from 'react';
import {
  ReactShortcutProvider,
  useShortcut,
} from '@rocketc/react-use-shortcuts';

function App() {
  return (
    <ReactShortcutProvider>
      <Main />
    </ReactShortcutProvider>
  );
}

function Main() {
  const { registerShortcut, unregisterShortcut } = useShortcut();

  useEffect(() => {
    registerShortcut('Ctrl+a', (event) => {
      console.log('You pressed Ctrl and A');
    });
    return () => {
      unregisterShortcut('Ctrl+a');
    };
  }, []);

  return <h1>Hello World!</h1>;
}

3. Register Scoped Shortcut

import React, { useEffect, useRef } from 'react';
import {
  ReactShortcutProvider,
  useShortcut,
} from '@rocketc/react-use-shortcuts';

function App() {
  return (
    <div id="root">
      <ReactShortcutProvider options={{ auto: false }}>
        <Main />
      </ReactShortcutProvider>
      <ReactShortcutProvider options={{ auto: false }}>
        <Main />
        <Main />
      </ReactShortcutProvider>
    </div>
  );
}

function Main() {
  const { registerShortcut, unregisterShortcut, attachElement } = useShortcut();

  const root = useRef<HTMLDivElement>(null);

  useEffect(() => {
    if (root.current) {
      return attachElement(root.current);
    }
  }, []);

  useEffect(() => {
    registerShortcut('Ctrl+a', (event) => {
      console.log('You pressed Ctrl and A');
    });
    return () => {
      unregisterShortcut('Ctrl+a');
    };
  }, []);

  return (
    <h1 ref={root} tabIndex={-1}>
      Hello World!
    </h1>
  );
}

‼️ Important: Set element tabIndex property to -1 to make the element focusable. Scoped shortcuts will not work without this.

4. Loose Mode

@rocketc/react-use-shortcuts works in strict mode by default (strict: true). Set strict: false to enable loose mode. This only affects the getCurrentKeyPressed API.

import React, { useEffect } from 'react';
import {
  ReactShortcutProvider,
  useShortcut,
} from '@rocketc/react-use-shortcuts';

function App() {
  return (
    <ReactShortcutProvider options={{ strict: false }}>
      <Main />
    </ReactShortcutProvider>
  );
}

function Main() {
  const { onKeyPressedChanged, getCurrentKeyPressed } = useShortcut();

  useEffect(() => {
    return onKeyPressedChanged((event) => {
      // If you pressed ControlLeft and A:
      // - strict mode: prints 'ControlLeft+A'
      // - loose mode: prints 'Ctrl+A'
      console.log(getCurrentKeyPressed());
      // event.detail indicates the event type: 'keydown' or 'keyup'
      console.log('Event type:', event.detail);
    });
  }, []);

  return <h1>Hello World!</h1>;
}

5. Dynamic Enable/Disable Shortcut

import React, { useEffect, useCallback, useState } from 'react';
import {
  ReactShortcutProvider,
  useShortcut,
} from '@rocketc/react-use-shortcuts';

function App() {
  return (
    <ReactShortcutProvider>
      <Main />
    </ReactShortcutProvider>
  );
}

function Main() {
  const {
    registerShortcut,
    unregisterShortcut,
    enableShortcut,
    disableShortcut,
  } = useShortcut();
  const [enable, setEnable] = useState<boolean>(true);

  const handleClick = useCallback(() => {
    setEnable((prev) => {
      if (prev) {
        disableShortcut('Ctrl+a');
      } else {
        enableShortcut('Ctrl+a');
      }
      return !prev;
    });
  }, []);

  useEffect(() => {
    registerShortcut('Ctrl+a', (event) => {
      console.log('You pressed Control and A');
    });
    return () => {
      unregisterShortcut('Ctrl+a');
    };
  }, []);

  return <button onClick={handleClick}>{enable ? 'disable' : 'enable'}</button>;
}

6. Multiple Callbacks for the Same Shortcut

You can register multiple callbacks for the same accelerator and manage them individually:

import React, { useEffect, useCallback } from 'react';
import {
  ReactShortcutProvider,
  useShortcut,
} from '@rocketc/react-use-shortcuts';

function App() {
  return (
    <ReactShortcutProvider>
      <Main />
    </ReactShortcutProvider>
  );
}

function Main() {
  const {
    registerShortcut,
    unregisterShortcut,
    enableShortcut,
    disableShortcut,
  } = useShortcut();

  useEffect(() => {
    const handler1 = () => console.log('Handler 1');
    const handler2 = () => console.log('Handler 2');

    // Register multiple handlers for the same shortcut
    registerShortcut('Ctrl+a', handler1);
    registerShortcut('Ctrl+a', handler2);

    // Disable only handler1
    disableShortcut('Ctrl+a', handler1);

    // Enable handler1 again
    enableShortcut('Ctrl+a', handler1);

    // Unregister only handler1
    unregisterShortcut('Ctrl+a', handler1);

    return () => {
      // Unregister all handlers for Ctrl+a
      unregisterShortcut('Ctrl+a');
    };
  }, []);

  return <h1>Hello World!</h1>;
}

7. Custom Event Filter

The default filter automatically filters out:

  • event.repeat (key repeat events)
  • event.isComposing (IME composition events, e.g., when typing Chinese/Japanese/Korean)
  • Events from INPUT, TEXTAREA, SELECT elements
  • Events from contentEditable elements

You can provide a custom filter to override this behavior:

import React, { useEffect } from 'react';
import {
  ReactShortcutProvider,
  useShortcut,
} from '@rocketc/react-use-shortcuts';

function App() {
  return (
    <ReactShortcutProvider
      options={{
        filter: (event) => (event.target as HTMLElement)?.tagName !== 'INPUT',
      }}
    >
      <Main />
    </ReactShortcutProvider>
  );
}

function Main() {
  const { registerShortcut, unregisterShortcut } = useShortcut();

  useEffect(() => {
    registerShortcut('Ctrl+a', (event) => {
      console.log('You pressed Control and A');
    });
    return () => {
      unregisterShortcut('Ctrl+a');
    };
  }, []);

  return (
    <div>
      <input />
    </div>
  );
}

8. Custom Key Aliases

You can define custom key name aliases to use in your shortcuts:

import React, { useEffect } from 'react';
import {
  ReactShortcutProvider,
  useShortcut,
} from '@rocketc/react-use-shortcuts';

function App() {
  return (
    <ReactShortcutProvider
      options={{
        alias: {
          Save: 'Ctrl',
          I: 'i',
        },
      }}
    >
      <Main />
    </ReactShortcutProvider>
  );
}

function Main() {
  const { registerShortcut, unregisterShortcut } = useShortcut();

  useEffect(() => {
    // Use the custom alias 'Save' instead of 'Ctrl'
    registerShortcut('Save+s', () => {
      console.log('Save shortcut triggered');
    });

    return () => {
      unregisterShortcut('Save+s');
    };
  }, []);

  return <h1>Hello World!</h1>;
}

9. Custom Debug Function

You can provide a custom debug function instead of using the default debug logger:

import React, { useEffect } from 'react';
import {
  ReactShortcutProvider,
  useShortcut,
} from '@rocketc/react-use-shortcuts';

function App() {
  return (
    <ReactShortcutProvider
      options={{
        debug: (...args) => {
          console.log('[Shortcut Debug]', ...args);
        },
      }}
    >
      <Main />
    </ReactShortcutProvider>
  );
}

function Main() {
  const { registerShortcut, unregisterShortcut } = useShortcut();

  useEffect(() => {
    registerShortcut('Ctrl+a', () => {
      console.log('You pressed Control and A');
    });
    return () => {
      unregisterShortcut('Ctrl+a');
    };
  }, []);

  return <h1>Hello World!</h1>;
}

API Reference

ReactShortcutProvider

React Context Provider component. Wrap your app or component tree with this provider.

Props:

interface ReactShortcutProviderProps {
  options?: ReactShortcutOptions;
  children?: ReactNode;
}

interface ReactShortcutOptions {
  strict?: boolean; // Default: false (strict mode by default)
  debug?: boolean | ((...args: any[]) => void); // Default: false
  auto?: boolean; // Default: true
  filter?: Filter;
  alias?: Record<string, string>;
  separator?: string; // Default: '+'
}

useShortcut

React Hook to access shortcut APIs.

Returns:

interface ReactShortcutContextValue {
  registerShortcut(
    accelerator: Accelerator,
    callback: KeyboardEventListener,
  ): boolean;
  unregisterShortcut(
    accelerator: Accelerator,
    cb?: KeyboardEventListener,
  ): boolean;
  enableShortcut(accelerator: Accelerator, cb?: KeyboardEventListener): boolean;
  disableShortcut(
    accelerator: Accelerator,
    cb?: KeyboardEventListener,
  ): boolean;
  isShortcutRegistered(accelerator: Accelerator): boolean;
  getCurrentKeyPressed(): Accelerator;
  onKeyPressedChanged(listener: KeyPressedChangedEventListener): Dispose;
  attachElement(ele: Window | HTMLElement): Dispose;
  getOptions(): ReactShortcutOptions;
  getShortcutRegisters(accelerator?: Accelerator): Array<ShortcutRegister>;
}

acceleratorParser

Utility object for parsing and validating accelerator strings. Re-exported from @rocketc/shortcuts.

import { acceleratorParser } from '@rocketc/react-use-shortcuts';

// Validate accelerator
const isValid = acceleratorParser.validate('Ctrl+a');

// Convert to loose mode
const loose = acceleratorParser.convertAcceleratorToLooseMode('ControlLeft+a');

// Parse accelerator
const parsed = acceleratorParser.parse('Ctrl+Shift+a');
console.log(parsed); // ['Ctrl', 'Shift', 'a']

// Check if key code name is supported
const isSupported = acceleratorParser.isKeyCodeNameSupported('Ctrl');
console.log(isSupported); // true

// Check if accelerators match
const isMatched = acceleratorParser.isAcceleratorMatched(
  'Ctrl+a',
  'ControlLeft+KeyA',
);
console.log(isMatched); // true

// Get default separator
const separator = acceleratorParser.defaultSeparator;
console.log(separator); // '+'

For complete API documentation, see @rocketc/shortcuts.

Shortcut Match Rules

See the Shortcut Match Rules section in @rocketc/shortcuts documentation.

Browser Compatibility

  • Chrome ≥ 48
  • Firefox ≥ 38
  • Safari ≥ 10.1
  • Edge ≥ 79

Core Library

This package is built on top of @rocketc/shortcuts, which provides the core shortcut functionality without React dependencies. If you need to use shortcuts in a non-React environment, use @rocketc/shortcuts directly.

Alternatives

Comparisons

| Features | @rocketc/react-use-shortcuts | react-hotkeys-hook | react-hot-keys | | ------------------------------------------ | -------------------------------- | ---------------------- | ------------------ | | Dynamic register | ✅ | ❌ | ❌ | | Page scoped register | ✅ | ✅ | ❌ | | Strict/Loose mode | ✅ | ❌ | ❌ | | Dynamic enable/disable shortcut registered | ✅ | ✅ | ❌ | | Normal key combinations | ❌ | ✅ | ✅ | | Namespace | ❌ | ❌ | ✅ | | Shortcuts validation | ✅ | ❌ | ❌ | | Used React ≤ 18.0.0 | ❌ | ❌ | ✅ |

License

Distributed under the MIT License. See LICENSE for more information.