Overview
Keyboard shortcuts that stay honest: chords, sequences, scopes, and a registry that can describe itself — so the shortcuts-help overlay is generated from the bindings that actually exist rather than hand-maintained beside them.
@absolutejs/hotkeysv0.1.1betaFrontend & UXFramework-agnostic keyboard shortcuts: chords, sequences, scopes and a self-describing binding registry.
bun add @absolutejs/hotkeysKeyboard shortcuts that stay honest: chords, sequences, scopes, and a registry that can describe itself — so the shortcuts-help overlay is generated from the bindings that actually exist rather than hand-maintained beside them.
mod is Meta on Apple platforms and Control everywhere else, so one
binding string is correct on every machine.
Sequences (g i) fire only when typed in order within a second; a wrong
key aborts rather than lingering.
Text entry is respected. Bindings don't fire while an input,
textarea or contenteditable has focus unless they pass allowInInput: true — typing "e" in a reply must never dismiss a thread.
A scope is a stack. Push one when a modal or a focused list takes over, and its bindings win over the app-wide ones until it pops.
when: () => boolean gates a binding at press time for finer conditions.
Bindings unregister with the component's effect scope, so a closed modal can't leave a live shortcut behind.
Only described bindings appear: if it isn't worth naming, it isn't worth teaching.
Outcomes
Keyboard shortcuts that stay honest: chords, sequences, scopes, and a registry that can describe itself — so the shortcuts-help overlay is generated from the bindings that actually exist rather than hand-maintained beside them.
mod is Meta on Apple platforms and Control everywhere else, so one
A scope is a stack. Push one when a modal or a focused list takes over, and its bindings win over the app-wide ones until it pops.
Hardening checklist
Follow in order
# @absolutejs/hotkeys
bun add @absolutejs/hotkeysWorking example for Core (no framework).
import { hotkeys, listenForHotkeys } from "@absolutejs/hotkeys";
const stop = listenForHotkeys();
hotkeys.register("j", selectNext, { description: "Next", group: "Navigation" });
hotkeys.register("mod+k", openPalette, { description: "Command palette" });
hotkeys.register("g i", goToInbox, { description: "Go to inbox" });A scope is a stack. Push one when a modal or a focused list takes over, and its bindings win over the app-wide ones until it pops.
hotkeys.register("escape", closeApp);
hotkeys.register("escape", closeModal, { scope: "modal" });
hotkeys.pushScope("modal"); // escape now closes the modal
hotkeys.popScope("modal"); // ...and the app-wide binding is backSupported entry points declared by this project’s package manifest. Internal dist paths are not part of the package contract.
Public package entry point declared in package.json.
Scripts declared by this project’s package manifest.
Search the declarations exported by the current package type files. Expand a symbol to inspect its source-backed signature.