Skip to main content
Version: 5.0

Advanced Usage

Using ts-key-enum for type-safe key names

It can be hard to remember whether the left arrow key is called ArrowLeft or LeftArrow. The ts-key-enum library provides TypeScript enums for all key names, giving you autocomplete and eliminating guesswork.

Install it:

npm install ts-key-enum

Use it in your code:

import { Key } from 'ts-key-enum'

useHotkeys(Key.Backspace, () => {
console.log('Delete pressed')
})

See the full list of available keys.


Building a help panel with metadata

You can attach a description and custom metadata to every hotkey. This makes it easy to build a dynamic help panel that lists all active shortcuts:

function useActiveHotkeys() {
// You would collect this from your components or a registry
const hotkeys = [
{ keys: 'ctrl+s', description: 'Save document', scope: 'editor' },
{ keys: 'ctrl+z', description: 'Undo', scope: 'editor' },
{ keys: 'esc', description: 'Close modal', scope: 'modal' },
];

return hotkeys;
}

function HelpPanel() {
const hotkeys = useActiveHotkeys();

return (
<div>
<h3>Keyboard Shortcuts</h3>
<ul>
{hotkeys.map(h => (
<li key={h.keys}>
<kbd>{h.keys}</kbd>{h.description}
</li>
))}
</ul>
</div>
);
}

When registering hotkeys, include the description option:

useHotkeys('ctrl+s', handleSave, {
description: 'Save the current document',
metadata: { category: 'file' },
});

Custom hooks built on useHotkeys

Wrapping useHotkeys in a custom hook keeps your components clean and enforces consistent behavior across your app:

function useEditorShortcuts() {
const { enableScope, disableScope } = useHotkeysContext();

useHotkeys('ctrl+s', saveDocument, {
scopes: 'editor',
preventDefault: true,
description: 'Save document',
});

useHotkeys('ctrl+z', undo, {
scopes: 'editor',
preventDefault: true,
description: 'Undo',
});

useHotkeys('ctrl+shift+z', redo, {
scopes: 'editor',
preventDefault: true,
description: 'Redo',
});

return { enableScope, disableScope };
}

Then in your editor component:

function Editor() {
useEditorShortcuts();

return <div>{/* editor content */}</div>;
}

Listening inside iframes

If your React app runs inside an iframe, pass the iframe's document object to bind hotkeys to that document instead of the main page:

import FrameComponent from 'react-frame-component'

function InsideFrameComponent() {
const { document } = useFrame()

useHotkeys('s', () => console.log('Triggered inside iframe'), { document })

return <div>....</div>
}

function App() {
return (
<FrameComponent>
<InsideFrameComponent/>
</FrameComponent>
)
}

Event listener options

You can pass custom event listener options to the underlying addEventListener call:

useHotkeys('ctrl+s', handleSave, {
eventListenerOptions: { passive: true, capture: true },
});

This is useful when you need fine-grained control over event propagation.