
Hotkeys.js is a dependency-free JavaScript library for binding keyboard shortcuts and key combinations in web applications. It handles single keys, modifier combinations such as Ctrl+K or Command+S, and multi-key shortcuts.
You can install it from npm, load the IIFE build directly in the browser, or import the ES module build. Scopes, custom target elements, keydown and keyup handling, shortcut filtering, programmatic triggers, and unbinding support common app-level keyboard controls.
Features:
- Single-key and multi-key keyboard shortcuts.
- Ctrl, Alt, Shift, Option, Control, and Command modifiers.
- Scoped shortcut groups for different application states.
- Keydown and keyup callback handling.
- Custom target elements and capture-phase listeners.
- Programmatic triggering and shortcut unbinding.
- Pressed-key inspection and registered shortcut lookup.
- Custom filtering for form fields and editable content.
Use Cases:
- Command palettes open from familiar shortcuts such as Ctrl+K or Command+K.
- Editors bind save, formatting, navigation, and document actions to the keyboard.
- Dashboards trigger global actions or switch application panels from key combinations.
- Complex interfaces activate different shortcut groups through named scopes.
How To Use Hotkeys.js:
Install with npm
Install hotkeys-js for bundler-based projects, then import the default hotkeys function.
npm install hotkeys-js --save
import hotkeys from 'hotkeys-js';
hotkeys('ctrl+k,command+k', function(event) {
event.preventDefault();
document.querySelector('#command-palette').classList.toggle('is-open');
});Load Hotkeys.js directly in the browser
The IIFE build exposes hotkeys as a global function and works well for a normal script-based page.
<script src="https://unpkg.com/hotkeys-js/dist/hotkeys-js.min.js"></script>
Register one or more shortcuts in a comma-separated string. The callback receives the native keyboard event and a handler object that includes the matched shortcut in handler.key.
hotkeys('ctrl+s,command+s,esc', function(event, handler) {
switch (handler.key) {
case 'ctrl+s':
case 'command+s':
event.preventDefault();
saveDocument();
break;
case 'esc':
closeActivePanel();
break;
}
});Use the ES module build in a browser
Modern browsers can import the ES module build from a CDN inside a type="module" script.
<script type="module">
import hotkeys from 'https://unpkg.com/hotkeys-js/dist/hotkeys-js.js';
hotkeys('ctrl+p,command+p', function(event) {
event.preventDefault();
openProjectSwitcher();
});
</script>Bind modifier keys and multi-key shortcuts
Hotkeys.js recognizes Shift, Alt, Ctrl, Control, Option, Command, and their symbol aliases. Three-key combinations such as ctrl+alt+enter also work.
hotkeys('shift+g,alt+n,ctrl+alt+enter', function(event, handler) {
console.log('Matched shortcut:', handler.key);
});Use scopes for different interface states
A scope groups shortcuts under a name. Only the active scope and the global all scope respond after hotkeys.setScope() changes the current scope.
hotkeys('ctrl+s,command+s', 'editor', function(event) {
event.preventDefault();
saveDocument();
});
hotkeys('esc', 'modal', function() {
closeModal();
});
// Activate editor shortcuts.
hotkeys.setScope('editor');
// Read the active scope.
console.log(hotkeys.getScope());Listen for keydown and keyup
Set keyup and keydown when the callback needs to distinguish between the press and release phases.
hotkeys('shift+p', {
keydown: true,
keyup: true
}, function(event, handler) {
console.log(event.type, handler.key);
});Bind shortcuts to a specific element
The element option attaches the keyboard listener to a chosen DOM element. This is useful for editors, panels, and other focused controls.
const editor = document.getElementById('editor');
hotkeys('ctrl+b,command+b', {
element: editor
}, function(event) {
event.preventDefault();
toggleBoldText();
});Change the shortcut separator
The default combination separator is +. Set splitKey when a shortcut includes the plus key itself.
hotkeys('ctrl-+', {
splitKey: '-'
}, function() {
zoomIn();
});Supported Keys:
Supported modifier names include shift, option, alt, ctrl, control, command, plus the ⇧, ⌥, and ⌘ symbols.
Special keys include backspace, tab, clear, enter, return, esc, escape, space, up, down, left, right, home, end, pageup, pagedown, del, delete, f1 through f19, and numpad keys such as num_0 through num_9. The fn key is not supported.
Configuration Options:
Pass an options object as the second argument when a shortcut needs a scope, a custom target element, event-phase control, or other binding behavior.
scope(string): Sets the scope in which the shortcut is active.element(HTMLElement): Binds the listener to a specific DOM element.keyup(boolean): Runs the callback when the key is released.keydown(boolean): Runs the callback when the key is pressed.splitKey(string): Changes the combination delimiter. The default delimiter is+.capture(boolean): Registers the listener in the capture phase.single(boolean): Keeps one callback for the binding and removes the previous callback when a new one is registered.
hotkeys('ctrl+alt+d', {
scope: 'dashboard',
element: document.getElementById('dashboard'),
keydown: true,
keyup: false,
splitKey: '+',
capture: true,
single: false
}, function(event, handler) {
console.log(handler.key);
});API Methods:
// Change the active scope.
hotkeys.setScope('editor');
// Read the active scope.
hotkeys.getScope();
// Delete a scope and its shortcuts.
hotkeys.deleteScope('editor');
// Delete a scope and switch to another scope.
hotkeys.deleteScope('editor', 'dashboard');
// Remove a shortcut from the current scope.
hotkeys.unbind('ctrl+s');
// Remove shortcuts from a named scope.
hotkeys.unbind('o, enter', 'files');
// Remove a specific callback.
function handleSave() {
saveDocument();
}
hotkeys('ctrl+s', handleSave);
hotkeys.unbind('ctrl+s', handleSave);
// Remove all registered shortcuts.
hotkeys.unbind();
// Check a key by name or key code.
hotkeys.isPressed('a');
hotkeys.isPressed(65);
// Trigger a registered shortcut.
hotkeys.trigger('ctrl+o');
// Trigger a shortcut in a named scope.
hotkeys.trigger('ctrl+o', 'files');
// Get key codes that are currently pressed.
hotkeys.getPressedKeyCodes();
// Get readable names for the currently pressed keys.
hotkeys.getPressedKeyString();
// Get registered shortcut information.
hotkeys.getAllKeyCodes();
// Release the global "hotkeys" variable and return the library reference.
const keyboardShortcuts = hotkeys.noConflict();Modifier state and public maps
The global API also exposes modifier-state properties and keyboard mapping objects.
// Modifier state. hotkeys.shift; hotkeys.ctrl; hotkeys.alt; hotkeys.option; hotkeys.control; hotkeys.cmd; hotkeys.command; // Keyboard maps. hotkeys.keyMap; hotkeys.modifier; hotkeys.modifierMap;
Keyboard Shortcuts In Input Fields:
Hotkeys.js ignores shortcuts from INPUT, SELECT, and TEXTAREA elements by default. Replace hotkeys.filter when a project needs a different rule.
This filter keeps shortcuts disabled in form fields and content-editable regions:
hotkeys.filter = function(event) {
const target = event.target || event.srcElement;
const tagName = target.tagName;
return !(
target.isContentEditable ||
tagName === 'INPUT' ||
tagName === 'SELECT' ||
tagName === 'TEXTAREA'
);
};Return true for every event when shortcuts must also run inside text inputs and other editable controls:
hotkeys.filter = function() {
return true;
};Alternatives:
- Add Custom Keyboard Shortcuts to Your Site with Hotkey.js
- Build Custom Keyboard Shortcuts with Keyboard-ShortcutX
- Custom Keybinds and Hotkeys in JavaScript – Keybind.js
FAQs:
Q: Does Hotkeys.js require jQuery?
A: No. Hotkeys.js has no runtime dependencies and works with plain JavaScript.
Q: Why does a Hotkeys.js shortcut stop working inside an input or textarea?
A: The default filter excludes INPUT, SELECT, and TEXTAREA elements. Replace hotkeys.filter when shortcuts need to run in those controls.
Q: How do I bind Ctrl and Command to the same action?
A: Register both combinations in the same binding, such as hotkeys('ctrl+s,command+s', callback).
Q: How do I activate shortcuts only in one part of an application?
A: Register the shortcuts under a named scope and activate that scope with hotkeys.setScope('scopeName').
Q: How do I remove a keyboard shortcut?
A: Call hotkeys.unbind() with the shortcut string. A scope or callback function can narrow which binding is removed.
Changelog:
v4.0.8 (09/10/2026)
- fix: support modern numeric key events
v4.0.7 (08/28/2026)
- Bugfixes
v4.0.4 (04/30/2026)
- Normalized Latin-layout key matching and stabilized browser tests.
v4.0.2 (02/25/2026)
- Removed CommonJS mutation from the ESM entry.
v4.0.1 (02/23/2026)
- Cleared pressed keys on fullscreen changes to prevent stuck key states.
v4.0.0 (12/22/2025)
- Major refactor and package-format updates.
v3.13.0 (12/08/2023)
- Added the
singleoption.
v3.12.0 (08/02/2023)
- Added the
getAllKeyCodes()API method.
v3.10.0 (09/07/2022)
- Added
getPressedKeyString().
v3.9.0 (04/22/2022)
- Added
trigger()and exposed keyboard mapping objects.
v3.6.0 (03/27/2019)
- Added three-key combination support.







