diff --git a/docs/framework/solid/reference/functions/createHeldKeyCodes.md b/docs/framework/solid/reference/functions/createHeldKeyCodes.md new file mode 100644 index 0000000..aeca5be --- /dev/null +++ b/docs/framework/solid/reference/functions/createHeldKeyCodes.md @@ -0,0 +1,53 @@ +--- +id: createHeldKeyCodes +title: createHeldKeyCodes +--- + +# Function: createHeldKeyCodes() + +```ts +function createHeldKeyCodes(): () => Record; +``` + +Defined in: [createHeldKeyCodes.ts:35](https://github.com/TanStack/hotkeys/blob/main/packages/solid-hotkeys/src/createHeldKeyCodes.ts#L35) + +SolidJS primitive that returns a signal of a map from currently held key names to their physical `event.code` values. + +This is useful for debugging which physical key was pressed (e.g. distinguishing +left vs right Shift via "ShiftLeft" / "ShiftRight"). + +This primitive uses `useStore` from `@tanstack/solid-store` to subscribe +to the global KeyStateTracker. + +## Returns + +Signal accessor for record mapping normalized key names to their `event.code` values + +```ts +(): Record; +``` + +### Returns + +`Record`\<`string`, `string`\> + +## Example + +```tsx +function KeyDebugDisplay() { + const heldKeys = createHeldKeys() + const heldCodes = createHeldKeyCodes() + + return ( +
+ + {(key) => ( + + {key} {heldCodes()[key]} + + )} + +
+ ) +} +``` diff --git a/docs/framework/solid/reference/functions/createHeldKeys.md b/docs/framework/solid/reference/functions/createHeldKeys.md new file mode 100644 index 0000000..5c32d4a --- /dev/null +++ b/docs/framework/solid/reference/functions/createHeldKeys.md @@ -0,0 +1,44 @@ +--- +id: createHeldKeys +title: createHeldKeys +--- + +# Function: createHeldKeys() + +```ts +function createHeldKeys(): () => string[]; +``` + +Defined in: [createHeldKeys.ts:26](https://github.com/TanStack/hotkeys/blob/main/packages/solid-hotkeys/src/createHeldKeys.ts#L26) + +SolidJS primitive that returns a signal of currently held keyboard keys. + +This primitive uses `useStore` from `@tanstack/solid-store` to subscribe +to the global KeyStateTracker and updates whenever keys are pressed +or released. + +## Returns + +Signal accessor for array of currently held key names + +```ts +(): string[]; +``` + +### Returns + +`string`[] + +## Example + +```tsx +function KeyDisplay() { + const heldKeys = createHeldKeys() + + return ( +
+ Currently pressed: {heldKeys().join(' + ') || 'None'} +
+ ) +} +``` diff --git a/docs/framework/solid/reference/functions/createHotkey.md b/docs/framework/solid/reference/functions/createHotkey.md new file mode 100644 index 0000000..be9c77f --- /dev/null +++ b/docs/framework/solid/reference/functions/createHotkey.md @@ -0,0 +1,88 @@ +--- +id: createHotkey +title: createHotkey +--- + +# Function: createHotkey() + +```ts +function createHotkey( + hotkey, + callback, + options): void; +``` + +Defined in: [createHotkey.ts:83](https://github.com/TanStack/hotkeys/blob/main/packages/solid-hotkeys/src/createHotkey.ts#L83) + +SolidJS primitive for registering a keyboard hotkey. + +Uses the singleton HotkeyManager for efficient event handling. +The callback receives both the keyboard event and a context object +containing the hotkey string and parsed hotkey. + +This primitive automatically tracks reactive dependencies and updates +the registration when options or the callback change. + +## Parameters + +### hotkey + +The hotkey string (e.g., 'Mod+S', 'Escape') or RawHotkey object (supports `mod` for cross-platform) + +`RegisterableHotkey` | () => `RegisterableHotkey` + +### callback + +`HotkeyCallback` + +The function to call when the hotkey is pressed + +### options + +Options for the hotkey behavior + +[`CreateHotkeyOptions`](../interfaces/CreateHotkeyOptions.md) | () => [`CreateHotkeyOptions`](../interfaces/CreateHotkeyOptions.md) + +## Returns + +`void` + +## Examples + +```tsx +function SaveButton() { + const [count, setCount] = createSignal(0) + + // Callback always has access to latest count value + createHotkey('Mod+S', (event, { hotkey }) => { + console.log(`Save triggered, count is ${count()}`) + handleSave() + }) + + return +} +``` + +```tsx +function Modal(props) { + // enabled option is reactive + createHotkey('Escape', () => { + props.onClose() + }, () => ({ enabled: props.isOpen })) + + return + + +} +``` + +```tsx +function Editor() { + const [editorRef, setEditorRef] = createSignal(null) + + // Scoped to a specific element - use accessor so hotkey waits for ref + createHotkey('Mod+S', save, () => ({ target: editorRef() })) + + return
...
+} +``` diff --git a/docs/framework/solid/reference/functions/createHotkeyRecorder.md b/docs/framework/solid/reference/functions/createHotkeyRecorder.md new file mode 100644 index 0000000..a708b20 --- /dev/null +++ b/docs/framework/solid/reference/functions/createHotkeyRecorder.md @@ -0,0 +1,64 @@ +--- +id: createHotkeyRecorder +title: createHotkeyRecorder +--- + +# Function: createHotkeyRecorder() + +```ts +function createHotkeyRecorder(options): SolidHotkeyRecorder; +``` + +Defined in: [createHotkeyRecorder.ts:61](https://github.com/TanStack/hotkeys/blob/main/packages/solid-hotkeys/src/createHotkeyRecorder.ts#L61) + +SolidJS primitive for recording keyboard shortcuts. + +This primitive provides a thin wrapper around the framework-agnostic `HotkeyRecorder` +class, managing all the complexity of capturing keyboard events, converting them +to hotkey strings, and handling edge cases like Escape to cancel or Backspace/Delete +to clear. + +This primitive uses `useStore` from `@tanstack/solid-store` to subscribe +to the recorder's store state (same pattern as useHotkeyRecorder in React). + +## Parameters + +### options + +Configuration options for the recorder (or accessor function) + +`HotkeyRecorderOptions` | () => `HotkeyRecorderOptions` + +## Returns + +[`SolidHotkeyRecorder`](../interfaces/SolidHotkeyRecorder.md) + +An object with recording state signals and control functions + +## Example + +```tsx +function ShortcutSettings() { + const [shortcut, setShortcut] = createSignal('Mod+S') + + const recorder = createHotkeyRecorder({ + onRecord: (hotkey) => { + setShortcut(hotkey) + }, + onCancel: () => { + console.log('Recording cancelled') + }, + }) + + return ( +
+ + +
Recording: {recorder.recordedHotkey()}
+
+
+ ) +} +``` diff --git a/docs/framework/solid/reference/functions/createHotkeySequence.md b/docs/framework/solid/reference/functions/createHotkeySequence.md new file mode 100644 index 0000000..faafb2d --- /dev/null +++ b/docs/framework/solid/reference/functions/createHotkeySequence.md @@ -0,0 +1,67 @@ +--- +id: createHotkeySequence +title: createHotkeySequence +--- + +# Function: createHotkeySequence() + +```ts +function createHotkeySequence( + sequence, + callback, + options): void; +``` + +Defined in: [createHotkeySequence.ts:50](https://github.com/TanStack/hotkeys/blob/main/packages/solid-hotkeys/src/createHotkeySequence.ts#L50) + +SolidJS primitive for registering a keyboard shortcut sequence (Vim-style). + +This primitive allows you to register multi-key sequences like 'g g' or 'd d' +that trigger when the full sequence is pressed within a timeout. + +## Parameters + +### sequence + +Array of hotkey strings that form the sequence (or accessor function) + +`HotkeySequence` | () => `HotkeySequence` + +### callback + +`HotkeyCallback` + +Function to call when the sequence is completed + +### options + +Options for the sequence behavior (or accessor function) + +[`CreateHotkeySequenceOptions`](../interfaces/CreateHotkeySequenceOptions.md) | () => [`CreateHotkeySequenceOptions`](../interfaces/CreateHotkeySequenceOptions.md) + +## Returns + +`void` + +## Example + +```tsx +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
...
+} +``` diff --git a/docs/framework/solid/reference/functions/createKeyHold.md b/docs/framework/solid/reference/functions/createKeyHold.md new file mode 100644 index 0000000..588f386 --- /dev/null +++ b/docs/framework/solid/reference/functions/createKeyHold.md @@ -0,0 +1,68 @@ +--- +id: createKeyHold +title: createKeyHold +--- + +# Function: createKeyHold() + +```ts +function createKeyHold(key): () => boolean; +``` + +Defined in: [createKeyHold.ts:46](https://github.com/TanStack/hotkeys/blob/main/packages/solid-hotkeys/src/createKeyHold.ts#L46) + +SolidJS primitive that returns whether a specific key is currently being held. + +This primitive uses `useStore` from `@tanstack/solid-store` to subscribe +to the global KeyStateTracker and uses a selector to determine if the +specified key is held. + +## Parameters + +### key + +The key to check (e.g., 'Shift', 'Control', 'A') - can be an accessor function + +`HeldKey` | () => `HeldKey` + +## Returns + +Signal accessor that returns true if the key is currently held down + +```ts +(): boolean; +``` + +### Returns + +`boolean` + +## Examples + +```tsx +function ShiftIndicator() { + const isShiftHeld = createKeyHold('Shift') + + return ( +
+ {isShiftHeld() ? 'Shift is pressed!' : 'Press Shift'} +
+ ) +} +``` + +```tsx +function ModifierIndicators() { + const ctrl = createKeyHold('Control') + const shift = createKeyHold('Shift') + const alt = createKeyHold('Alt') + + return ( +
+ Ctrl + Shift + Alt +
+ ) +} +``` diff --git a/docs/framework/solid/reference/functions/useDefaultHotkeysOptions.md b/docs/framework/solid/reference/functions/useDefaultHotkeysOptions.md new file mode 100644 index 0000000..6f4dc1d --- /dev/null +++ b/docs/framework/solid/reference/functions/useDefaultHotkeysOptions.md @@ -0,0 +1,16 @@ +--- +id: useDefaultHotkeysOptions +title: useDefaultHotkeysOptions +--- + +# Function: useDefaultHotkeysOptions() + +```ts +function useDefaultHotkeysOptions(): HotkeysProviderOptions; +``` + +Defined in: [HotkeysProvider.tsx:44](https://github.com/TanStack/hotkeys/blob/main/packages/solid-hotkeys/src/HotkeysProvider.tsx#L44) + +## Returns + +[`HotkeysProviderOptions`](../interfaces/HotkeysProviderOptions.md) diff --git a/docs/framework/solid/reference/functions/useHotkeysContext.md b/docs/framework/solid/reference/functions/useHotkeysContext.md new file mode 100644 index 0000000..1a0175c --- /dev/null +++ b/docs/framework/solid/reference/functions/useHotkeysContext.md @@ -0,0 +1,16 @@ +--- +id: useHotkeysContext +title: useHotkeysContext +--- + +# Function: useHotkeysContext() + +```ts +function useHotkeysContext(): HotkeysContextValue | null; +``` + +Defined in: [HotkeysProvider.tsx:40](https://github.com/TanStack/hotkeys/blob/main/packages/solid-hotkeys/src/HotkeysProvider.tsx#L40) + +## Returns + +`HotkeysContextValue` \| `null` diff --git a/docs/framework/solid/reference/index.md b/docs/framework/solid/reference/index.md new file mode 100644 index 0000000..ded4220 --- /dev/null +++ b/docs/framework/solid/reference/index.md @@ -0,0 +1,29 @@ +--- +id: "@tanstack/solid-hotkeys" +title: "@tanstack/solid-hotkeys" +--- + +# @tanstack/solid-hotkeys + +## Interfaces + +- [CreateHotkeyOptions](interfaces/CreateHotkeyOptions.md) +- [CreateHotkeySequenceOptions](interfaces/CreateHotkeySequenceOptions.md) +- [HotkeysProviderOptions](interfaces/HotkeysProviderOptions.md) +- [HotkeysProviderProps](interfaces/HotkeysProviderProps.md) +- [SolidHotkeyRecorder](interfaces/SolidHotkeyRecorder.md) + +## Variables + +- [HotkeysProvider](variables/HotkeysProvider.md) + +## Functions + +- [createHeldKeyCodes](functions/createHeldKeyCodes.md) +- [createHeldKeys](functions/createHeldKeys.md) +- [createHotkey](functions/createHotkey.md) +- [createHotkeyRecorder](functions/createHotkeyRecorder.md) +- [createHotkeySequence](functions/createHotkeySequence.md) +- [createKeyHold](functions/createKeyHold.md) +- [useDefaultHotkeysOptions](functions/useDefaultHotkeysOptions.md) +- [useHotkeysContext](functions/useHotkeysContext.md) diff --git a/docs/framework/solid/reference/interfaces/CreateHotkeyOptions.md b/docs/framework/solid/reference/interfaces/CreateHotkeyOptions.md new file mode 100644 index 0000000..5dfeb0b --- /dev/null +++ b/docs/framework/solid/reference/interfaces/CreateHotkeyOptions.md @@ -0,0 +1,28 @@ +--- +id: CreateHotkeyOptions +title: CreateHotkeyOptions +--- + +# Interface: CreateHotkeyOptions + +Defined in: [createHotkey.ts:17](https://github.com/TanStack/hotkeys/blob/main/packages/solid-hotkeys/src/createHotkey.ts#L17) + +## Extends + +- `Omit`\<`HotkeyOptions`, `"target"`\> + +## Properties + +### target? + +```ts +optional target: HTMLElement | Document | Window | null; +``` + +Defined in: [createHotkey.ts:25](https://github.com/TanStack/hotkeys/blob/main/packages/solid-hotkeys/src/createHotkey.ts#L25) + +The DOM element to attach the event listener to. +Can be a direct DOM element, an accessor (for reactive targets that become +available after mount), or null. Defaults to document. +When using scoped targets, pass an accessor: () => ({ target: elementSignal() }) +so the hotkey waits for the element to be attached before registering. diff --git a/docs/framework/solid/reference/interfaces/CreateHotkeySequenceOptions.md b/docs/framework/solid/reference/interfaces/CreateHotkeySequenceOptions.md new file mode 100644 index 0000000..433f554 --- /dev/null +++ b/docs/framework/solid/reference/interfaces/CreateHotkeySequenceOptions.md @@ -0,0 +1,24 @@ +--- +id: CreateHotkeySequenceOptions +title: CreateHotkeySequenceOptions +--- + +# Interface: CreateHotkeySequenceOptions + +Defined in: [createHotkeySequence.ts:10](https://github.com/TanStack/hotkeys/blob/main/packages/solid-hotkeys/src/createHotkeySequence.ts#L10) + +## Extends + +- `Omit`\<`SequenceOptions`, `"enabled"`\> + +## Properties + +### enabled? + +```ts +optional enabled: boolean; +``` + +Defined in: [createHotkeySequence.ts:15](https://github.com/TanStack/hotkeys/blob/main/packages/solid-hotkeys/src/createHotkeySequence.ts#L15) + +Whether the sequence is enabled. Defaults to true. diff --git a/docs/framework/solid/reference/interfaces/HotkeysProviderOptions.md b/docs/framework/solid/reference/interfaces/HotkeysProviderOptions.md new file mode 100644 index 0000000..07683f2 --- /dev/null +++ b/docs/framework/solid/reference/interfaces/HotkeysProviderOptions.md @@ -0,0 +1,38 @@ +--- +id: HotkeysProviderOptions +title: HotkeysProviderOptions +--- + +# Interface: HotkeysProviderOptions + +Defined in: [HotkeysProvider.tsx:7](https://github.com/TanStack/hotkeys/blob/main/packages/solid-hotkeys/src/HotkeysProvider.tsx#L7) + +## Properties + +### hotkey? + +```ts +optional hotkey: Partial; +``` + +Defined in: [HotkeysProvider.tsx:8](https://github.com/TanStack/hotkeys/blob/main/packages/solid-hotkeys/src/HotkeysProvider.tsx#L8) + +*** + +### hotkeyRecorder? + +```ts +optional hotkeyRecorder: Partial; +``` + +Defined in: [HotkeysProvider.tsx:9](https://github.com/TanStack/hotkeys/blob/main/packages/solid-hotkeys/src/HotkeysProvider.tsx#L9) + +*** + +### hotkeySequence? + +```ts +optional hotkeySequence: Partial; +``` + +Defined in: [HotkeysProvider.tsx:10](https://github.com/TanStack/hotkeys/blob/main/packages/solid-hotkeys/src/HotkeysProvider.tsx#L10) diff --git a/docs/framework/solid/reference/interfaces/HotkeysProviderProps.md b/docs/framework/solid/reference/interfaces/HotkeysProviderProps.md new file mode 100644 index 0000000..d053d68 --- /dev/null +++ b/docs/framework/solid/reference/interfaces/HotkeysProviderProps.md @@ -0,0 +1,28 @@ +--- +id: HotkeysProviderProps +title: HotkeysProviderProps +--- + +# Interface: HotkeysProviderProps + +Defined in: [HotkeysProvider.tsx:19](https://github.com/TanStack/hotkeys/blob/main/packages/solid-hotkeys/src/HotkeysProvider.tsx#L19) + +## Properties + +### children + +```ts +children: Element; +``` + +Defined in: [HotkeysProvider.tsx:20](https://github.com/TanStack/hotkeys/blob/main/packages/solid-hotkeys/src/HotkeysProvider.tsx#L20) + +*** + +### defaultOptions? + +```ts +optional defaultOptions: HotkeysProviderOptions; +``` + +Defined in: [HotkeysProvider.tsx:21](https://github.com/TanStack/hotkeys/blob/main/packages/solid-hotkeys/src/HotkeysProvider.tsx#L21) diff --git a/docs/framework/solid/reference/interfaces/SolidHotkeyRecorder.md b/docs/framework/solid/reference/interfaces/SolidHotkeyRecorder.md new file mode 100644 index 0000000..f164063 --- /dev/null +++ b/docs/framework/solid/reference/interfaces/SolidHotkeyRecorder.md @@ -0,0 +1,88 @@ +--- +id: SolidHotkeyRecorder +title: SolidHotkeyRecorder +--- + +# Interface: SolidHotkeyRecorder + +Defined in: [createHotkeyRecorder.ts:7](https://github.com/TanStack/hotkeys/blob/main/packages/solid-hotkeys/src/createHotkeyRecorder.ts#L7) + +## Properties + +### cancelRecording() + +```ts +cancelRecording: () => void; +``` + +Defined in: [createHotkeyRecorder.ts:17](https://github.com/TanStack/hotkeys/blob/main/packages/solid-hotkeys/src/createHotkeyRecorder.ts#L17) + +Cancel recording without saving + +#### Returns + +`void` + +*** + +### isRecording() + +```ts +isRecording: () => boolean; +``` + +Defined in: [createHotkeyRecorder.ts:9](https://github.com/TanStack/hotkeys/blob/main/packages/solid-hotkeys/src/createHotkeyRecorder.ts#L9) + +Whether recording is currently active + +#### Returns + +`boolean` + +*** + +### recordedHotkey() + +```ts +recordedHotkey: () => Hotkey | null; +``` + +Defined in: [createHotkeyRecorder.ts:11](https://github.com/TanStack/hotkeys/blob/main/packages/solid-hotkeys/src/createHotkeyRecorder.ts#L11) + +The currently recorded hotkey (for live preview) + +#### Returns + +`Hotkey` \| `null` + +*** + +### startRecording() + +```ts +startRecording: () => void; +``` + +Defined in: [createHotkeyRecorder.ts:13](https://github.com/TanStack/hotkeys/blob/main/packages/solid-hotkeys/src/createHotkeyRecorder.ts#L13) + +Start recording a new hotkey + +#### Returns + +`void` + +*** + +### stopRecording() + +```ts +stopRecording: () => void; +``` + +Defined in: [createHotkeyRecorder.ts:15](https://github.com/TanStack/hotkeys/blob/main/packages/solid-hotkeys/src/createHotkeyRecorder.ts#L15) + +Stop recording (same as cancel) + +#### Returns + +`void` diff --git a/docs/framework/solid/reference/variables/HotkeysProvider.md b/docs/framework/solid/reference/variables/HotkeysProvider.md new file mode 100644 index 0000000..4fcdfa9 --- /dev/null +++ b/docs/framework/solid/reference/variables/HotkeysProvider.md @@ -0,0 +1,12 @@ +--- +id: HotkeysProvider +title: HotkeysProvider +--- + +# Variable: HotkeysProvider + +```ts +const HotkeysProvider: ParentComponent; +``` + +Defined in: [HotkeysProvider.tsx:26](https://github.com/TanStack/hotkeys/blob/main/packages/solid-hotkeys/src/HotkeysProvider.tsx#L26) diff --git a/examples/react/useHeldKeys/package.json b/examples/react/useHeldKeys/package.json index 46c1f43..dc9feab 100644 --- a/examples/react/useHeldKeys/package.json +++ b/examples/react/useHeldKeys/package.json @@ -18,7 +18,7 @@ "devDependencies": { "@tanstack/react-devtools": "0.9.5", "@tanstack/react-hotkeys-devtools": "^0.1.0", - "@types/react": "^19.2.13", + "@types/react": "^19.2.14", "@types/react-dom": "^19.2.3", "@vitejs/plugin-react": "^5.1.4", "typescript": "5.9.3", diff --git a/examples/react/useHotkey/package.json b/examples/react/useHotkey/package.json index cdabf09..2b51dc1 100644 --- a/examples/react/useHotkey/package.json +++ b/examples/react/useHotkey/package.json @@ -18,7 +18,7 @@ "devDependencies": { "@tanstack/react-devtools": "0.9.5", "@tanstack/react-hotkeys-devtools": "^0.1.0", - "@types/react": "^19.2.13", + "@types/react": "^19.2.14", "@types/react-dom": "^19.2.3", "@vitejs/plugin-react": "^5.1.4", "typescript": "5.9.3", diff --git a/examples/react/useHotkeyRecorder/package.json b/examples/react/useHotkeyRecorder/package.json index 8f19d65..9806249 100644 --- a/examples/react/useHotkeyRecorder/package.json +++ b/examples/react/useHotkeyRecorder/package.json @@ -18,7 +18,7 @@ "devDependencies": { "@tanstack/react-devtools": "0.9.5", "@tanstack/react-hotkeys-devtools": "^0.1.0", - "@types/react": "^19.2.13", + "@types/react": "^19.2.14", "@types/react-dom": "^19.2.3", "@vitejs/plugin-react": "^5.1.4", "typescript": "5.9.3", diff --git a/examples/react/useHotkeySequence/package.json b/examples/react/useHotkeySequence/package.json index 5e8397f..016703e 100644 --- a/examples/react/useHotkeySequence/package.json +++ b/examples/react/useHotkeySequence/package.json @@ -18,7 +18,7 @@ "devDependencies": { "@tanstack/react-devtools": "0.9.5", "@tanstack/react-hotkeys-devtools": "^0.1.0", - "@types/react": "^19.2.13", + "@types/react": "^19.2.14", "@types/react-dom": "^19.2.3", "@vitejs/plugin-react": "^5.1.4", "typescript": "5.9.3", diff --git a/examples/react/useKeyhold/package.json b/examples/react/useKeyhold/package.json index a03ed9e..b9f03ed 100644 --- a/examples/react/useKeyhold/package.json +++ b/examples/react/useKeyhold/package.json @@ -18,7 +18,7 @@ "devDependencies": { "@tanstack/react-devtools": "0.9.5", "@tanstack/react-hotkeys-devtools": "^0.1.0", - "@types/react": "^19.2.13", + "@types/react": "^19.2.14", "@types/react-dom": "^19.2.3", "@vitejs/plugin-react": "^5.1.4", "typescript": "5.9.3", diff --git a/examples/solid/createHeldKeys/index.html b/examples/solid/createHeldKeys/index.html new file mode 100644 index 0000000..774d162 --- /dev/null +++ b/examples/solid/createHeldKeys/index.html @@ -0,0 +1,11 @@ + + + + + createHeldKeys - TanStack Hotkeys Solid Example + + +
+ + + diff --git a/examples/solid/createHeldKeys/package.json b/examples/solid/createHeldKeys/package.json new file mode 100644 index 0000000..7920f11 --- /dev/null +++ b/examples/solid/createHeldKeys/package.json @@ -0,0 +1,21 @@ +{ + "name": "@tanstack/hotkeys-example-solid-create-held-keys", + "private": true, + "type": "module", + "scripts": { + "dev": "vite --port=3069", + "build": "vite build", + "preview": "vite preview" + }, + "dependencies": { + "@tanstack/devtools-utils": "^0.3.0", + "@tanstack/solid-devtools": "0.7.25", + "@tanstack/solid-hotkeys": "workspace:*", + "@tanstack/solid-hotkeys-devtools": "workspace:*", + "solid-js": "^1.9.11" + }, + "devDependencies": { + "vite": "^7.3.1", + "vite-plugin-solid": "^2.11.10" + } +} diff --git a/examples/solid/createHeldKeys/src/index.css b/examples/solid/createHeldKeys/src/index.css new file mode 100644 index 0000000..bff2498 --- /dev/null +++ b/examples/solid/createHeldKeys/src/index.css @@ -0,0 +1,116 @@ +* { + box-sizing: border-box; +} +body { + margin: 0; + font-family: + system-ui, + -apple-system, + sans-serif; + background: #f5f5f5; + color: #333; +} +.app { + max-width: 800px; + margin: 0 auto; + padding: 20px; +} +header h1 { + margin: 0 0 10px; + color: #0066cc; +} +header p { + color: #666; + margin: 0; + max-width: 500px; + margin: 0 auto; +} +.demo-section { + background: white; + border-radius: 12px; + padding: 24px; + margin-bottom: 24px; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); +} +.demo-section h2 { + margin: 0 0 16px; + font-size: 20px; +} +.demo-section ul { + margin: 0; + padding-left: 20px; +} +.demo-section li { + margin-bottom: 8px; +} +kbd { + background: linear-gradient(180deg, #f8f8f8 0%, #e8e8e8 100%); + border: 1px solid #ccc; + border-bottom-width: 2px; + border-radius: 4px; + padding: 2px 8px; + font-family: monospace; + font-size: 13px; +} +kbd.large { + font-size: 24px; + padding: 8px 16px; + display: inline-flex; + flex-direction: column; + align-items: center; + gap: 2px; +} +.key-display { + display: flex; + align-items: center; + justify-content: center; + gap: 12px; + min-height: 80px; + flex-wrap: wrap; + background: #f8f9fa; + border-radius: 8px; + padding: 20px; +} +.key-display .plus { + font-size: 24px; + color: #666; +} +.placeholder { + color: #999; + font-style: italic; +} +.stats { + text-align: center; + margin-top: 16px; + font-size: 16px; + color: #666; +} +.code-block { + background: #1e1e1e; + color: #d4d4d4; + padding: 16px; + border-radius: 8px; + overflow-x: auto; + font-size: 13px; +} +.history-list { + list-style: none; + padding: 0; + margin: 0 0 16px; +} +.history-list li { + padding: 8px 12px; + background: #f0f0f0; + border-radius: 4px; + margin-bottom: 4px; + font-family: monospace; + font-size: 14px; +} +button { + background: #0066cc; + color: white; + border: none; + padding: 10px 20px; + border-radius: 6px; + cursor: pointer; +} diff --git a/examples/solid/createHeldKeys/src/index.tsx b/examples/solid/createHeldKeys/src/index.tsx new file mode 100644 index 0000000..19a434c --- /dev/null +++ b/examples/solid/createHeldKeys/src/index.tsx @@ -0,0 +1,139 @@ +/* @refresh reload */ +import { render } from 'solid-js/web' +import { createSignal, createEffect } from 'solid-js' +import { + formatKeyForDebuggingDisplay, + createHeldKeys, + createHeldKeyCodes, + HotkeysProvider, +} from '@tanstack/solid-hotkeys' +import { hotkeysDevtoolsPlugin } from '@tanstack/solid-hotkeys-devtools' +import { TanStackDevtools } from '@tanstack/solid-devtools' +import './index.css' + +function App() { + const heldKeys = createHeldKeys() + const heldCodes = createHeldKeyCodes() + const [history, setHistory] = createSignal>([]) + + createEffect(() => { + const keys = heldKeys() + if (keys.length > 0) { + const combo = keys.map((k) => formatKeyForDebuggingDisplay(k)).join(' + ') + setHistory((h) => { + if (h[h.length - 1] !== combo) { + return [...h.slice(-9), combo] + } + return h + }) + } + }) + + return ( +
+
+

createHeldKeys

+

+ Returns a signal of all currently pressed keys. Useful for displaying + key combinations or building custom shortcut recording. +

+
+ +
+
+

Currently Held Keys

+
+ {heldKeys().length > 0 ? ( + heldKeys().map((key, index) => { + const code = heldCodes()[key] + return ( + <> + {index > 0 && +} + + {formatKeyForDebuggingDisplay(key)} + {code && code !== key && ( + + {formatKeyForDebuggingDisplay(code, { + source: 'code', + })} + + )} + + + ) + }) + ) : ( + Press any keys... + )} +
+
+ Keys held: {heldKeys().length} +
+
+ +
+

Usage

+
{`import { createHeldKeys } from '@tanstack/solid-hotkeys'
+
+function KeyDisplay() {
+  const heldKeys = createHeldKeys()
+
+  return (
+    
+ Currently pressed: {heldKeys().join(' + ') || 'None'} +
+ ) +}`}
+
+ +
+

Try These Combinations

+
    +
  • + Hold Shift + Control + A +
  • +
  • Press multiple letter keys at once
  • +
  • Hold modifiers and watch them appear
  • +
  • Release keys one by one
  • +
+
+ +
+

Recent Combinations

+ {history().length > 0 ? ( +
    + {history().map((combo, i) => ( +
  • {combo}
  • + ))} +
+ ) : ( +

Press some key combinations...

+ )} + +
+ +
+

Use Cases

+
    +
  • Building a keyboard shortcut recorder
  • +
  • Displaying currently held keys to users
  • +
  • Debugging keyboard input
  • +
  • Creating key combination tutorials
  • +
+
+
+ + +
+ ) +} + +const root = document.getElementById('root')! +render( + () => ( + + + + ), + root, +) diff --git a/examples/solid/createHeldKeys/tsconfig.json b/examples/solid/createHeldKeys/tsconfig.json new file mode 100644 index 0000000..ec9b6aa --- /dev/null +++ b/examples/solid/createHeldKeys/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "target": "ESNext", + "lib": ["DOM", "DOM.Iterable", "ESNext"], + "module": "ESNext", + "skipLibCheck": true, + "moduleResolution": "Bundler", + "jsx": "preserve", + "strict": true, + "types": ["vite/client"] + }, + "include": ["src", "vite.config.ts"] +} diff --git a/examples/solid/createHeldKeys/vite.config.ts b/examples/solid/createHeldKeys/vite.config.ts new file mode 100644 index 0000000..4095d9b --- /dev/null +++ b/examples/solid/createHeldKeys/vite.config.ts @@ -0,0 +1,6 @@ +import { defineConfig } from 'vite' +import solid from 'vite-plugin-solid' + +export default defineConfig({ + plugins: [solid()], +}) diff --git a/examples/solid/createHotkey/index.html b/examples/solid/createHotkey/index.html new file mode 100644 index 0000000..54978bf --- /dev/null +++ b/examples/solid/createHotkey/index.html @@ -0,0 +1,14 @@ + + + + + + + createHotkey - TanStack Hotkeys Solid Example + + + +
+ + + diff --git a/examples/solid/createHotkey/package.json b/examples/solid/createHotkey/package.json new file mode 100644 index 0000000..518936a --- /dev/null +++ b/examples/solid/createHotkey/package.json @@ -0,0 +1,26 @@ +{ + "name": "@tanstack/hotkeys-example-solid-create-hotkey", + "private": true, + "type": "module", + "scripts": { + "dev": "vite --port=3069", + "build": "vite build", + "preview": "vite preview", + "lint": "eslint .", + "lint:fix": "eslint . --fix", + "test:types": "tsc" + }, + "dependencies": { + "@tanstack/devtools-utils": "^0.3.0", + "@tanstack/solid-devtools": "0.7.25", + "@tanstack/solid-hotkeys": "workspace:*", + "@tanstack/solid-hotkeys-devtools": "workspace:*", + "solid-js": "^1.9.11" + }, + "devDependencies": { + "@types/node": "^25.2.3", + "typescript": "5.9.3", + "vite": "^7.3.1", + "vite-plugin-solid": "^2.11.10" + } +} diff --git a/examples/solid/createHotkey/src/index.css b/examples/solid/createHotkey/src/index.css new file mode 100644 index 0000000..e9f3ca9 --- /dev/null +++ b/examples/solid/createHotkey/src/index.css @@ -0,0 +1,212 @@ +* { + box-sizing: border-box; +} +body { + margin: 0; + font-family: + system-ui, + -apple-system, + sans-serif; + background: #f5f5f5; + color: #333; +} +.app { + max-width: 800px; + margin: 0 auto; + padding: 20px; +} +header { + text-align: center; + margin-bottom: 40px; +} +header h1 { + margin: 0 0 10px; + color: #0066cc; +} +header p { + color: #666; + margin: 0; +} +.demo-section { + background: white; + border-radius: 12px; + padding: 24px; + margin-bottom: 24px; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); +} +.demo-section h2 { + margin: 0 0 12px; + font-size: 20px; +} +.demo-section p { + margin: 0 0 12px; +} +kbd { + background: linear-gradient(180deg, #f8f8f8 0%, #e8e8e8 100%); + border: 1px solid #ccc; + border-bottom-width: 2px; + border-radius: 4px; + padding: 2px 8px; + font-family: monospace; + font-size: 13px; +} +.counter { + font-size: 28px; + font-weight: bold; + color: #0066cc; + margin: 16px 0; +} +.hint { + font-size: 13px; + color: #888; + font-style: italic; +} +.info-box { + background: #e3f2fd; + border-radius: 8px; + padding: 12px 16px; + margin: 20px 0; +} +button { + background: #0066cc; + color: white; + border: none; + padding: 10px 20px; + border-radius: 6px; + cursor: pointer; + font-size: 14px; +} +button:hover { + background: #0052a3; +} +.code-block { + background: #1e1e1e; + color: #d4d4d4; + padding: 16px; + border-radius: 8px; + overflow-x: auto; + font-size: 13px; + line-height: 1.5; + margin-top: 16px; +} +.hotkey-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + gap: 12px; + margin: 16px 0; +} +.hotkey-grid > div { + display: flex; + align-items: center; + gap: 8px; + padding: 8px 12px; + background: #f8f9fa; + border-radius: 6px; + font-size: 14px; +} +.hotkey-grid kbd { + flex-shrink: 0; +} + +/* Scoped shortcuts section */ +.scoped-section { + margin-top: 40px; +} + +.scoped-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); + gap: 24px; + margin: 24px 0; +} + +.scoped-area { + background: #f8f9fa; + border: 2px dashed #0066cc; + border-radius: 8px; + padding: 20px; + position: relative; +} + +.scoped-area:focus-within { + border-color: #0052a3; + border-style: solid; + background: #f0f7ff; + box-shadow: 0 0 0 3px rgba(0, 102, 204, 0.1); +} + +.scoped-area h3 { + margin: 0 0 12px; + font-size: 18px; + color: #0066cc; +} + +.scoped-area .hotkey-list { + margin: 12px 0; +} + +.scoped-area .hotkey-list > div { + display: flex; + align-items: center; + gap: 8px; + padding: 6px 0; + font-size: 14px; +} + +.scoped-editor { + width: 100%; + margin: 12px 0; + padding: 12px; + border: 1px solid #ddd; + border-radius: 6px; + font-family: 'Courier New', monospace; + font-size: 14px; + resize: vertical; + min-height: 120px; +} + +.scoped-editor:focus { + outline: 2px solid #0066cc; + outline-offset: 2px; + border-color: #0066cc; +} + +/* Modal styles */ +.modal-overlay { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(0, 0, 0, 0.5); + display: flex; + align-items: center; + justify-content: center; + z-index: 1000; +} + +.modal-content { + background: white; + border-radius: 12px; + padding: 24px; + max-width: 500px; + width: 90%; + max-height: 80vh; + overflow-y: auto; + box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2); +} + +.modal-content:focus { + outline: 3px solid #0066cc; + outline-offset: 2px; +} + +.modal-content h3 { + margin: 0 0 16px; + font-size: 20px; + color: #0066cc; +} + +.modal-content button { + margin-top: 16px; +} diff --git a/examples/solid/createHotkey/src/index.tsx b/examples/solid/createHotkey/src/index.tsx new file mode 100644 index 0000000..c7d23ee --- /dev/null +++ b/examples/solid/createHotkey/src/index.tsx @@ -0,0 +1,654 @@ +/* @refresh reload */ +import { render } from 'solid-js/web' +import { createSignal, createEffect, Show } from 'solid-js' +import { + formatForDisplay, + createHotkey, + HotkeysProvider, +} from '@tanstack/solid-hotkeys' +import { hotkeysDevtoolsPlugin } from '@tanstack/solid-hotkeys-devtools' +import { TanStackDevtools } from '@tanstack/solid-devtools' +import type { Hotkey } from '@tanstack/solid-hotkeys' +import './index.css' + +function App() { + const [lastHotkey, setLastHotkey] = createSignal(null) + const [saveCount, setSaveCount] = createSignal(0) + const [incrementCount, setIncrementCount] = createSignal(0) + const [enabled, setEnabled] = createSignal(true) + const [activeTab, setActiveTab] = createSignal(1) + const [navigationCount, setNavigationCount] = createSignal(0) + const [functionKeyCount, setFunctionKeyCount] = createSignal(0) + const [multiModifierCount, setMultiModifierCount] = createSignal(0) + const [editingKeyCount, setEditingKeyCount] = createSignal(0) + + const [modalOpen, setModalOpen] = createSignal(false) + const [editorContent, setEditorContent] = createSignal('') + const [sidebarShortcutCount, setSidebarShortcutCount] = createSignal(0) + const [modalShortcutCount, setModalShortcutCount] = createSignal(0) + const [editorShortcutCount, setEditorShortcutCount] = createSignal(0) + + const [sidebarRef, setSidebarRef] = createSignal(null) + const [modalRef, setModalRef] = createSignal(null) + const [editorRef, setEditorRef] = createSignal( + null, + ) + + createHotkey('Mod+S', (_event, { hotkey, parsedHotkey }) => { + setLastHotkey(hotkey) + setSaveCount((c) => c + 1) + console.log('Hotkey triggered:', hotkey) + console.log('Parsed hotkey:', parsedHotkey) + }) + + createHotkey( + 'Mod+K', + (_event, { hotkey }) => { + setLastHotkey(hotkey) + setIncrementCount((c) => c + 1) + }, + { requireReset: true }, + ) + + createHotkey( + 'Mod+E', + (_event, { hotkey }) => { + setLastHotkey(hotkey) + alert('This hotkey can be toggled!') + }, + () => ({ enabled: enabled() }), + ) + + createHotkey('Mod+1', () => { + setLastHotkey('Mod+1') + setActiveTab(1) + }) + createHotkey('Mod+2', () => { + setLastHotkey('Mod+2') + setActiveTab(2) + }) + createHotkey('Mod+3', () => { + setLastHotkey('Mod+3') + setActiveTab(3) + }) + createHotkey('Mod+4', () => { + setLastHotkey('Mod+4') + setActiveTab(4) + }) + createHotkey('Mod+5', () => { + setLastHotkey('Mod+5') + setActiveTab(5) + }) + + createHotkey('Shift+ArrowUp', () => { + setLastHotkey('Shift+ArrowUp') + setNavigationCount((c) => c + 1) + }) + createHotkey('Shift+ArrowDown', () => { + setLastHotkey('Shift+ArrowDown') + setNavigationCount((c) => c + 1) + }) + createHotkey('Alt+ArrowLeft', () => { + setLastHotkey('Alt+ArrowLeft') + setNavigationCount((c) => c + 1) + }) + createHotkey('Alt+ArrowRight', () => { + setLastHotkey('Alt+ArrowRight') + setNavigationCount((c) => c + 1) + }) + createHotkey('Mod+Home', () => { + setLastHotkey('Mod+Home') + setNavigationCount((c) => c + 1) + }) + createHotkey('Mod+End', () => { + setLastHotkey('Mod+End') + setNavigationCount((c) => c + 1) + }) + createHotkey('Control+PageUp', () => { + setLastHotkey('Control+PageUp') + setNavigationCount((c) => c + 1) + }) + createHotkey('Control+PageDown', () => { + setLastHotkey('Control+PageDown') + setNavigationCount((c) => c + 1) + }) + + createHotkey('Meta+F4', () => { + setLastHotkey('Alt+F4') + setFunctionKeyCount((c) => c + 1) + alert('Alt+F4 pressed (normally closes window)') + }) + createHotkey('Control+F5', () => { + setLastHotkey('Control+F5') + setFunctionKeyCount((c) => c + 1) + }) + createHotkey('Mod+F1', () => { + setLastHotkey('Mod+F1') + setFunctionKeyCount((c) => c + 1) + }) + createHotkey('Shift+F10', () => { + setLastHotkey('Shift+F10') + setFunctionKeyCount((c) => c + 1) + }) + + createHotkey('Mod+Shift+S', () => { + setLastHotkey('Mod+Shift+S') + setMultiModifierCount((c) => c + 1) + }) + createHotkey('Mod+Shift+Z', () => { + setLastHotkey('Mod+Shift+Z') + setMultiModifierCount((c) => c + 1) + }) + createHotkey({ key: 'A', ctrl: true, alt: true }, () => { + setLastHotkey('Control+Alt+A') + setMultiModifierCount((c) => c + 1) + }) + createHotkey('Control+Shift+N', () => { + setLastHotkey('Control+Shift+N') + setMultiModifierCount((c) => c + 1) + }) + createHotkey('Mod+Alt+T', () => { + setLastHotkey('Mod+Alt+T') + setMultiModifierCount((c) => c + 1) + }) + createHotkey('Control+Alt+Shift+X', () => { + setLastHotkey('Control+Alt+Shift+X') + setMultiModifierCount((c) => c + 1) + }) + + createHotkey('Mod+Enter', () => { + setLastHotkey('Mod+Enter') + setEditingKeyCount((c) => c + 1) + }) + createHotkey('Shift+Enter', () => { + setLastHotkey('Shift+Enter') + setEditingKeyCount((c) => c + 1) + }) + createHotkey('Mod+Backspace', () => { + setLastHotkey('Mod+Backspace') + setEditingKeyCount((c) => c + 1) + }) + createHotkey('Mod+Delete', () => { + setLastHotkey('Mod+Delete') + setEditingKeyCount((c) => c + 1) + }) + createHotkey('Control+Tab', () => { + setLastHotkey('Control+Tab') + setEditingKeyCount((c) => c + 1) + }) + createHotkey('Shift+Tab', () => { + setLastHotkey('Shift+Tab') + setEditingKeyCount((c) => c + 1) + }) + createHotkey('Mod+Space', () => { + setLastHotkey('Mod+Space') + setEditingKeyCount((c) => c + 1) + }) + + createHotkey({ key: 'Escape' }, () => { + setLastHotkey(null) + setSaveCount(0) + setIncrementCount(0) + setNavigationCount(0) + setFunctionKeyCount(0) + setMultiModifierCount(0) + setEditingKeyCount(0) + setActiveTab(1) + }) + createHotkey('F12', () => { + setLastHotkey('F12') + setFunctionKeyCount((c) => c + 1) + }) + + createEffect(() => { + if (modalOpen()) { + modalRef()?.focus() + } + }) + + createHotkey( + 'Mod+B', + () => { + setLastHotkey('Mod+B') + setSidebarShortcutCount((c) => c + 1) + alert( + 'Sidebar shortcut triggered! This only works when the sidebar area is focused.', + ) + }, + () => ({ target: sidebarRef() }), + ) + createHotkey( + 'Mod+N', + () => { + setLastHotkey('Mod+N') + setSidebarShortcutCount((c) => c + 1) + }, + () => ({ target: sidebarRef() }), + ) + + createHotkey( + 'Escape', + () => { + setLastHotkey('Escape') + setModalShortcutCount((c) => c + 1) + setModalOpen(false) + }, + () => ({ target: modalRef(), enabled: modalOpen() }), + ) + createHotkey( + 'Mod+Enter', + () => { + setLastHotkey('Mod+Enter') + setModalShortcutCount((c) => c + 1) + alert('Modal submit shortcut!') + }, + () => ({ target: modalRef(), enabled: modalOpen() }), + ) + + createHotkey( + 'Mod+S', + () => { + setLastHotkey('Mod+S') + setEditorShortcutCount((c) => c + 1) + const content = editorContent() + alert( + `Editor content saved: "${content.substring(0, 50)}${content.length > 50 ? '...' : ''}"`, + ) + }, + () => ({ target: editorRef() }), + ) + createHotkey( + 'Mod+/', + () => { + setLastHotkey('Mod+/') + setEditorShortcutCount((c) => c + 1) + setEditorContent((prev) => prev + '\n// Comment added via shortcut') + }, + () => ({ target: editorRef() }), + ) + createHotkey( + 'Mod+K', + () => { + setLastHotkey('Mod+K') + setEditorShortcutCount((c) => c + 1) + setEditorContent('') + }, + () => ({ target: editorRef() }), + ) + + return ( +
+
+

createHotkey

+

+ Register keyboard shortcuts with callback context containing the + hotkey and parsed hotkey information. +

+
+ +
+
+

Basic Hotkey

+

+ Press {formatForDisplay('Mod+S')} to trigger +

+
Save triggered: {saveCount()}x
+
{`createHotkey('Mod+S', (_event, { hotkey, parsedHotkey }) => {
+  console.log('Hotkey:', hotkey)
+  console.log('Parsed:', parsedHotkey)
+})`}
+
+ +
+

With requireReset

+

+ Hold {formatForDisplay('Mod+K')} — only increments once + until you release all keys +

+
Increment: {incrementCount()}
+

+ This prevents repeated triggering while holding the keys down. + Release all keys to allow re-triggering. +

+
{`createHotkey(
+  'Mod+K',
+  (event, { hotkey }) => {
+    setCount(c => c + 1)
+  },
+  { requireReset: true }
+)`}
+
+ +
+

Conditional Hotkey

+

+ {formatForDisplay('Mod+E')} is currently{' '} + {enabled() ? 'enabled' : 'disabled'} +

+ +
{`const [enabled, setEnabled] = createSignal(true)
+
+createHotkey(
+  'Mod+E',
+  (event, { hotkey }) => {
+    alert('Triggered!')
+  },
+  () => ({ enabled: enabled() })
+)`}
+
+ +
+

Number Key Combinations

+

Common for tab/section switching:

+
+
+ {formatForDisplay('Mod+1')} → Tab 1 +
+
+ {formatForDisplay('Mod+2')} → Tab 2 +
+
+ {formatForDisplay('Mod+3')} → Tab 3 +
+
+ {formatForDisplay('Mod+4')} → Tab 4 +
+
+ {formatForDisplay('Mod+5')} → Tab 5 +
+
+
Active Tab: {activeTab()}
+
{`createHotkey('Mod+1', () => setActiveTab(1))
+createHotkey('Mod+2', () => setActiveTab(2))
+`}
+
+ +
+

Navigation Key Combinations

+

Selection and navigation shortcuts:

+
+
+ {formatForDisplay('Shift+ArrowUp')} — Select up +
+
+ {formatForDisplay('Shift+ArrowDown')} — Select down +
+
+ {formatForDisplay('Alt+ArrowLeft')} — Navigate back +
+
+ {formatForDisplay('Alt+ArrowRight')} — Navigate forward +
+
+ {formatForDisplay('Mod+Home')} — Go to start +
+
+ {formatForDisplay('Mod+End')} — Go to end +
+
+ {formatForDisplay('Control+PageUp')} — Previous page +
+
+ {formatForDisplay('Control+PageDown')} — Next page +
+
+
Navigation triggered: {navigationCount()}x
+
{`createHotkey('Shift+ArrowUp', () => selectUp())
+createHotkey('Alt+ArrowLeft', () => navigateBack())
+createHotkey('Mod+Home', () => goToStart())
+createHotkey('Control+PageUp', () => previousPage())`}
+
+ +
+

Function Key Combinations

+

System and application shortcuts:

+
+
+ {formatForDisplay('Alt+F4')} — Close window +
+
+ {formatForDisplay('Control+F5')} — Hard refresh +
+
+ {formatForDisplay('Mod+F1')} — Help +
+
+ {formatForDisplay('Shift+F10')} — Context menu +
+
+ {formatForDisplay('F12')} — DevTools +
+
+
+ Function keys triggered: {functionKeyCount()}x +
+
{`createHotkey('Alt+F4', () => closeWindow())
+createHotkey('Control+F5', () => hardRefresh())
+createHotkey('Mod+F1', () => showHelp())
+createHotkey('F12', () => openDevTools())`}
+
+ +
+

Multi-Modifier Combinations

+

Complex shortcuts with multiple modifiers:

+
+
+ {formatForDisplay('Mod+Shift+S')} — Save As +
+
+ {formatForDisplay('Mod+Shift+Z')} — Redo +
+
+ {formatForDisplay('Control+Alt+A')} — Special action +
+
+ {formatForDisplay('Control+Shift+N')} — New incognito +
+
+ {formatForDisplay('Mod+Alt+T')} — Toggle theme +
+
+ {formatForDisplay('Control+Alt+Shift+X')} — Triple + modifier +
+
+
+ Multi-modifier triggered: {multiModifierCount()}x +
+
{`createHotkey('Mod+Shift+S', () => saveAs())
+createHotkey('Mod+Shift+Z', () => redo())
+createHotkey('Control+Alt+A', () => specialAction())
+createHotkey('Control+Alt+Shift+X', () => complexAction())`}
+
+ +
+

Editing Key Combinations

+

Text editing and form shortcuts:

+
+
+ {formatForDisplay('Mod+Enter')} — Submit form +
+
+ {formatForDisplay('Shift+Enter')} — New line +
+
+ {formatForDisplay('Mod+Backspace')} — Delete word +
+
+ {formatForDisplay('Mod+Delete')} — Delete forward +
+
+ {formatForDisplay('Control+Tab')} — Next tab +
+
+ {formatForDisplay('Shift+Tab')} — Previous field +
+
+ {formatForDisplay('Mod+Space')} — Toggle +
+
+
+ Editing keys triggered: {editingKeyCount()}x +
+
{`createHotkey('Mod+Enter', () => submitForm())
+createHotkey('Shift+Enter', () => insertNewline())
+createHotkey('Mod+Backspace', () => deleteWord())
+createHotkey('Control+Tab', () => nextTab())
+createHotkey('Mod+Space', () => toggle())`}
+
+ + +
+ Last triggered: {formatForDisplay(lastHotkey()!)} +
+
+ +

+ Press Escape to reset all counters +

+ +
+

Scoped Keyboard Shortcuts

+

+ Shortcuts can be scoped to specific DOM elements using the{' '} + target option. Use an accessor for reactive targets:{' '} + () => ({ target: ref() }) +

+ +
+
+

Sidebar (Scoped Area)

+

Click here to focus, then try:

+
+
+ {formatForDisplay('Mod+B')} — Trigger sidebar + action +
+
+ {formatForDisplay('Mod+N')} — New item +
+
+
+ Sidebar shortcuts: {sidebarShortcutCount()}x +
+

+ These shortcuts only work when this sidebar area is focused or + contains focus. +

+
+ +
+

Modal Dialog

+ + + + +
+ +
+

Text Editor (Scoped)

+

Focus the editor below and try:

+
+
+ {formatForDisplay('Mod+S')} — Save editor content +
+
+ {formatForDisplay('Mod+/')} — Add comment +
+
+ {formatForDisplay('Mod+K')} — Clear editor +
+
+