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

@accelint/hotkey-manager

v1.0.1

Published

A React-focused global hotkey system that prevents conflicts and manages keyboard shortcuts efficiently.

Readme

@accelint/hotkey-manager

A React-focused global hotkey system that prevents conflicts and manages keyboard shortcuts efficiently.

Features

  • Singleton Management: Each hotkey is bound only once, regardless of how many components use it
  • Automatic Cleanup: Hotkeys are automatically removed when components unmount
  • Conflict Prevention: Ensures each keyboard shortcut triggers only one action
  • Cross-Platform Support: Adapts to both Windows and macOS keyboard conventions
  • Input Field Safety: Disables hotkeys when typing in forms and text fields
  • SSR Compatible: Works with Server-Side Rendering and React Server Components
  • OS Hotkey Detection: Identifies conflicts with system shortcuts (Coming Soon)

Quick Start

The hotkey manager works with React's component lifecycle. Hotkeys are bound when components mount and only unbound when all components using that hotkey unmount. This reference-counting approach means a hotkey remains active as long as at least one component needs it:

// 1. Enable the hotkey bindings
// src/apps/layout.tsx
import { globalBind } from '@accelint/hotkey-manager';

globalBind();
// 2. Register your hotkey and define what it does
// src/hotkeys/toggle-grid.ts
import { registerHotkey, Keycode } from '@accelint/hotkey-manager';
import { gridStore } from '../stores/grid';

export const toggleGridManager = registerHotkey({
  id: 'toggle-grid',
  key: {
    code: Keycode.KeyG
  },
  // Using onKeyUp is recommended for most simple actions
  onKeyUp: () => gridStore().toggleVisibility(),
});
// 3. Then use the hotkey in your component
// src/layers/grid-layer.tsx
import { useHotkey } from '@accelint/hotkey-manager';
import { toggleGridManager } from '../hotkeys/toggle-grid';

export function GridLayer() {
  // This activates the hotkey when the component mounts
  // and deactivates it when unmounted
  useHotkey(toggleGridManager);

  // Rest of component code...
}

How to Use

Key Concept: Shared Hotkey Instances

An important feature of this library is that it maintains a single instance of each hotkey, even when multiple components use it. For example:

  • If ComponentA and ComponentB both use the same hotkey manager (like toggleGridManager)
  • The hotkey is bound when the first component mounts
  • It remains active even if one component unmounts
  • It's only fully unbound when all components using it unmount

This reference-counting system ensures efficient hotkey management and prevents duplicate listeners.

Step 1: Register Your Hotkey

Use registerHotkey to create a reusable hotkey manager:

import { registerHotkey, Keycode } from '@accelint/hotkey-manager';

export const toggleTagsManager = registerHotkey({
  id: 'toggle-tags',  // An identifier for this hotkey
  key: {
    code: Keycode.KeyT,  // The 'T' key
    alt: true           // Must press Alt+T
  },
  onKeyUp: () => someAction()  // Function to run when key is released
});

Step 2: Use the Hotkey in Components

Use useHotkey with your manager to automatically handle binding and unbinding:

import { useHotkey } from '@accelint/hotkey-manager';
import { toggleTagsManager } from '../hotkeys/toggle-tags';

function TextLabelLayer() {
  // This activates the Alt+T hotkey
  useHotkey(toggleTagsManager);

  return (
    // DeckGL Layer...
  );
}

Manual Control

For more control, useHotkey returns the manager with methods for manual binding:

import { useHotkey } from '@accelint/hotkey-manager';
import { toggleTagsManager } from '../hotkeys/toggle-tags';

function ConditionalHotkeyComponent() {
  const manager = useHotkey(toggleTagsManager);
  const [isEnabled, setIsEnabled] = useState(false);

  useEffect(() => {
    if (isEnabled) {
      manager.forceBind();
    } else {
      manager.forceUnbind();
    }
  }, [isEnabled, manager]);

  return (
    <div>
      <button onClick={() => setIsEnabled(!isEnabled)}>
        {isEnabled ? 'Disable' : 'Enable'} Hotkey
      </button>
    </div>
  );
}

Key Combinations

Basic Keys

The key property defines what keyboard input triggers your hotkey. The code field is required and uses standard keyboard event codes (available in the Keycode enum).

// Define a simple 'T' key hotkey
key: {
  code: Keycode.KeyT
}

Using code instead of character values ensures consistency across keyboard layouts and languages.

Modifier Keys

Add modifiers to create key combinations:

// Define Shift+T
key: {
  code: Keycode.KeyT,
  shift: true
}

// Define Alt+T
key: {
  code: Keycode.KeyT,
  alt: true
}

// Define Shift+Alt+T
key: {
  code: Keycode.KeyT,
  alt: true,
  shift: true
}

Available modifiers:

  • shift: The Shift key
  • alt: The Alt key (Option on macOS)
  • ctrl: The Control key
  • meta: The Windows key or Command (⌘) key on macOS

Multiple Key Bindings

Bind the same action to multiple keys by using an array:

key: [
  { code: Keycode.KeyS, ctrl: true },  // Ctrl+S
  { code: Keycode.F12 }                // F12
]

Your action receives information about which key triggered it:

onKeyDown: (event, key) => {
  if (key.code === Keycode.KeyS) {
    // Ctrl+S was pressed
  } else if (key.code === Keycode.F12) {
    // F12 was pressed
  }
}

OS and Browser Conflicts

Be cautious when using ctrl and meta key combinations, as many of these are reserved by operating systems and browsers. The hotkey manager will still attempt to handle these combinations, but the OS or browser may intercept them before your application receives the event. When possible, prefer combinations with alt or custom keys that don't conflict with system shortcuts.

Platform Adaptation

Automatic macOS Conversion

By default, the library automatically converts Windows-style shortcuts to macOS conventions:

  • ctrl+s becomes cmd+s on macOS
  • meta+s becomes ctrl+s on macOS

To disable this behavior for a specific hotkey:

key: {
  code: Keycode.KeyS,
  ctrl: true,
  autoMacStyle: false  // Keep as Ctrl+S on all platforms
}

Custom Platform Shortcuts

For more control over platform differences:

import { registerHotkey, Keycode, isMac } from '@accelint/hotkey-manager';

export const platformSaveManager = registerHotkey({
  id: 'platform-save',
  key: isMac
    ? { code: Keycode.KeyS, meta: true, autoMacStyle: false }  // Cmd+S on macOS
    : { code: Keycode.KeyS, ctrl: true, autoMacStyle: false }, // Ctrl+S on other platforms
  onKeyUp: () => someAction()
});

Actions

You can define up to three types of actions for each hotkey:

  1. onKeyDown: Triggered immediately when the key is pressed
  2. onKeyHeld: Triggered when the key is held down for a certain time
  3. onKeyUp: Triggered when the key is released

Important Behavior: By default, if both onKeyHeld and onKeyUp are defined for a hotkey and the held action is triggered, the onKeyUp action will not fire when the key is released. You can override this with the alwaysTriggerKeyUp: true option.

Best Practice: Use onKeyUp rather than onKeyDown for simple actions. This maintains UX consistency with onKeyHeld behavior, as most actions should happen either on long press or release, not on initial press.

Example with All Actions

export const zoomManager = registerHotkey({
  id: 'zoom',
  key: { code: Keycode.KeyZ },
  // Triggered on initial press
  onKeyDown: () => startZoom(),

  // Triggered after holding for 1 second (default)
  onKeyHeld: () => activateContinuousZoom(),

  // Triggered on release (unless onKeyHeld fired)
  onKeyUp: () => finishZoom(),

  // Configure hold detection time (in milliseconds)
  heldThresholdMs: 500,
  // Also trigger onKeyUp even if onKeyHeld was triggered
  alwaysTriggerKeyUp: true
})

Using in Libraries

When including this package in a library:

  1. List @accelint/hotkey-manager as a peer dependency
  2. Allow users to customize your hotkey bindings
  3. Avoid hardcoding hotkeys that might conflict with common OS shortcuts

This ensures only one hotkey manager instance exists in the application, preventing conflicts between different libraries.