@omniaura/solid-hotkeys
v0.1.1
Published
SolidJS adapter for TanStack Hotkeys - keyboard shortcuts made easy
Maintainers
Readme
@omniaura/solid-hotkeys
SolidJS adapter for TanStack Hotkeys - keyboard shortcuts made easy
Features
✅ Type-safe hotkey bindings - Template strings (Mod+Shift+S, Escape) or parsed objects
✅ Cross-platform - Mod key automatically maps to Cmd on macOS, Ctrl on Windows/Linux
✅ Sequence support - Vim-style multi-key sequences (g g, d d)
✅ Key state tracking - Track which keys are currently held down
✅ Hotkey recording - Built-in UI helpers for letting users define their own shortcuts
✅ SolidJS primitives - Reactive primitives that work seamlessly with SolidJS
Installation
npm install @omniaura/solid-hotkeys @tanstack/hotkeys
# or
bun add @omniaura/solid-hotkeys @tanstack/hotkeys
# or
pnpm add @omniaura/solid-hotkeys @tanstack/hotkeysQuick Start
import { createHotkey } from "@omniaura/solid-hotkeys";
function App() {
createHotkey("Mod+S", (event) => {
event.preventDefault();
console.log("Save!");
});
return <div>Press Cmd/Ctrl+S to save</div>;
}Usage
Basic Hotkey
import { createHotkey } from "@omniaura/solid-hotkeys";
function SaveButton() {
createHotkey("Mod+S", (event, { hotkey }) => {
event.preventDefault();
handleSave();
});
return <button>Save (Cmd/Ctrl+S)</button>;
}Conditional Hotkeys
import { createHotkey } from "@omniaura/solid-hotkeys";
import { Show, createSignal } from "solid-js";
function Modal(props) {
// Hotkey only active when modal is open
createHotkey("Escape", () => props.onClose(), () => ({
enabled: props.isOpen,
}));
return (
<Show when={props.isOpen}>
<div class="modal">Press Escape to close</div>
</Show>
);
}Scoped Hotkeys
import { createHotkey } from "@omniaura/solid-hotkeys";
function Editor() {
let editorRef: HTMLDivElement | undefined;
// Hotkey only works when editor is focused
createHotkey("Mod+B", () => {
toggleBold();
}, { target: editorRef });
return <div ref={editorRef} contentEditable />;
}Hotkey Sequences (Vim-style)
import { createHotkeySequence } from "@omniaura/solid-hotkeys";
function VimEditor() {
// 'g g' to go to top
createHotkeySequence(["G", "G"], () => {
scrollToTop();
});
// 'd d' to delete line
createHotkeySequence(["D", "D"], () => {
deleteLine();
});
// 'd i w' to delete inner word
createHotkeySequence(["D", "I", "W"], () => {
deleteInnerWord();
}, { timeout: 500 });
return <div>Try Vim shortcuts!</div>;
}Track Held Keys
import { createHeldKeys, createKeyHold } from "@omniaura/solid-hotkeys";
import { For } from "solid-js";
function KeyTracker() {
const heldKeys = createHeldKeys();
const shiftHeld = createKeyHold("Shift");
return (
<div>
<div>Shift: {shiftHeld() ? "Pressed" : "Not pressed"}</div>
<div>
All held keys:
<For each={heldKeys()}>{(key) => <kbd>{key}</kbd>}</For>
</div>
</div>
);
}Hotkey Recorder
import { createHotkeyRecorder } from "@omniaura/solid-hotkeys";
import { createSignal, Show } from "solid-js";
function ShortcutSettings() {
const [shortcut, setShortcut] = createSignal("Mod+S");
const recorder = createHotkeyRecorder({
onRecord: (hotkey) => {
setShortcut(hotkey);
},
onCancel: () => {
console.log("Recording cancelled");
},
});
return (
<div>
<div>Current shortcut: {shortcut()}</div>
<button onClick={recorder.startRecording}>
{recorder.isRecording() ? "Recording..." : "Edit Shortcut"}
</button>
<Show when={recorder.recordedHotkey()}>
<div>Preview: {recorder.recordedHotkey()}</div>
</Show>
</div>
);
}Global Configuration
import { HotkeysProvider } from "@omniaura/solid-hotkeys";
function App() {
return (
<HotkeysProvider
defaultOptions={{
hotkey: {
preventDefault: true,
enabled: true,
},
hotkeySequence: {
timeout: 1000,
},
}}
>
<YourApp />
</HotkeysProvider>
);
}API
createHotkey(hotkey, callback, options?)
Register a keyboard hotkey.
hotkey: String like"Mod+S"or"Escape", or accessor functioncallback: Function called when hotkey is pressedoptions: Optional configuration (or accessor function for reactive options)
Options:
enabled: Whether the hotkey is active (default:true)preventDefault: Prevent default browser behavior (default:false)stopPropagation: Stop event propagation (default:false)target: DOM element to attach listener to (default:document)platform: Override platform detection
createHotkeySequence(sequence, callback, options?)
Register a multi-key sequence (Vim-style).
sequence: Array of hotkey strings like["G", "G"], or accessor functioncallback: Function called when sequence completesoptions: Optional configuration (or accessor function)
Options:
enabled: Whether sequence detection is active (default:true)timeout: Max time between keys in ms (default:1000)platform: Override platform detection
createHeldKeys()
Returns a signal accessor for array of currently held keys.
const heldKeys = createHeldKeys();
// heldKeys() => ["Shift", "A"]createHeldKeyCodes()
Returns a signal accessor for map of held keys to their physical key codes.
const heldCodes = createHeldKeyCodes();
// heldCodes() => { "Shift": "ShiftLeft", "A": "KeyA" }createKeyHold(key)
Returns a signal accessor that's true when specific key is held.
const isShiftHeld = createKeyHold("Shift");
// isShiftHeld() => true/falsecreateHotkeyRecorder(options)
Hotkey recording interface.
Options:
onRecord: Callback when hotkey is recordedonCancel: Callback when recording is cancelled
Returns:
isRecording: Signal accessor for recording staterecordedHotkey: Signal accessor for current hotkey previewstartRecording: Function to start recordingstopRecording: Function to stop recordingcancelRecording: Function to cancel recording
HotkeysProvider
Optional provider for global configuration.
Cross-Platform Keys
Use Mod for cross-platform modifier:
Mod+S→Cmd+Son macOS,Ctrl+Son Windows/LinuxMod+Shift+P→Cmd+Shift+Pon macOS,Ctrl+Shift+Pelsewhere
Related
- TanStack Hotkeys - The core library
- solid-grab - Context grabbing for SolidJS
License
MIT © omniaura
