@svelte-put/shortcut
GithubCompatible with or powered directly by Svelte runes.
Installation
npm install --save-dev @svelte-put/shortcutpnpm add -D @svelte-put/shortcutyarn add -D @svelte-put/shortcutNew to Svelte 5? See Migration Guides.
Quick Start
The minimal example below shows how to register a global shortcut for Ctrl + K (Cmd + K on macOS).
<script lang="ts">
import { shortcut, type ShortcutEventDetail } from '@svelte-put/shortcut';
function handleK(detail: ShortcutEventDetail) {
console.log('attached node:', detail.node);
console.log('original trigger config:', detail.trigger);
}
</script>
<svelte:window
use:shortcut={{
trigger: {
key: 'k',
modifier: ['ctrl', 'meta'],
callback: handleK,
},
}}
/>Trigger
The trigger option take either one single trigger definition...
<svelte:window
use:shortcut={{ trigger: { key: 'k', modifier: 'ctrl' } }}
/>...or multiple ones in an array...
<svelte:window
use:shortcut={{
trigger: [
{ key: 'c', modifier: 'ctrl' },
{ key: 'v', modifier: 'ctrl' },
],
}}
/>You can use multiple use:shortcut with one trigger definition in each.
<svelte:window
use:shortcut={{ trigger: { key: 'c', modifier: 'ctrl' } }}
use:shortcut={{ trigger: { key: 'v', modifier: 'ctrl' } }}
/>This approach does take up some additional memory. It should be negligible in most cases but if your application is performance-critical, it is recommend to provide all triggers in one use:shortcut as shown in the multiple-triggers.svelte example.
Modifier
Each ShortcutTrigger can specify either one or multiple modifiers (ctrl, meta, alt, shift) via trigger.modifier in both AND & OR fashions.
Catch all
When left as undefined, trigger.modifier means "don't check for modifiers".
<svelte:window
use:shortcut={{
trigger: {
key: 'k',
},
}}
/>No modifier
Set trigger.modifier to false or null for keys that expect no modifier.
<svelte:window
use:shortcut={{
trigger: {
key: 'Escape',
modifier: false,
},
}}
/>Single Modifier
Set trigger.modifier to one of the modifiers (ctrl, meta, alt, shift) to listen for that modifier.
<svelte:window
use:shortcut={{
// ctrl+k
trigger: {
key: 'k',
modifier: 'ctrl',
},
}}
/>One of Many Modifiers (OR)
Use a flat array of modifiers to trigger when one of them is pressed.
<svelte:window
use:shortcut={{
// ctrl+k or meta+k
trigger: {
key: 'k',
modifier: ['ctrl', 'meta'],
},
}}
/>All of Modifiers (AND)
Wrap multiple modifiers in a subarray to trigger only when all modifiers are pressed at the same time.
<svelte:window
use:shortcut={{
// ctrl+shift+K
trigger: {
key: 'K',
modifier: [['ctrl', 'shift']],
},
}}
/>Notice that the key option in the above example is set to a capital K. This is because shift is specified as a modifier; when shift and k are pressed down at the same time, KeyboardEvent.key value will be K. You can use this site to test your key combinations.
Mix & Match
Use a combination of OR and AND to create complex modifier combinations.
<svelte:window
use:shortcut={{
// ctrl+alt+Delete or meta+Delete
trigger: {
key: 'Delete',
modifier: [['ctrl', 'alt'], 'meta'],
},
}}
/>Handler
Handlers can be provided via either trigger.callback...
<script lang="ts">
import { shortcut, type ShortcutEventDetail } from '@svelte-put/shortcut';
function toggleCommandPalette(detail: ShortcutEventDetail) {
console.log('Action was placed on:', details.node);
console.log('Trigger:', details.trigger);
// ...
}
</script>
<svelte:window
use:shortcut={{
trigger: {
key: 'k',
modifier: ['ctrl', 'meta'],
callback: toggleCommandPalette,
},
}}
/>...or onshortcut CustomEvent:
<script lang="ts">
import { shortcut, type ShortcutEventDetail } from '@svelte-put/shortcut';
function handleShortcuts(event: CustomEvent<ShortcutEventDetail>) {
if (event.detail.trigger.id === 'toggle-command-palette') {
// ...
}
}
</script>
<svelte:window
use:shortcut={{
trigger: {
key: 'k',
modifier: ['ctrl', 'meta'],
id: 'toggle-command-palette',
},
}}
onshortcut={handleShortcuts}
/>trigger.id is specified in the handler-custom-event.svelte example to conveniently help identify the trigger in the onshortcut event listener.
The two approaches are equivalent and depend on your aesthetic preference when multiple shortcuts are defined. trigger.callback is bound directly to its trigger definition, whereas onshortcut is a centralized event listener for all shortcuts.
You should use only one of the two presented approaches and NOT both to avoid duplicate event handling.
Event Type
@svelte-put/shortcut support keydown (default) or keyup event type. You may change this via
the type option.
<svelte:window
use:shortcut={{
trigger: {
key: 'k',
modifier: ['ctrl', 'meta'],
},
type: 'keyup',
}}
/>Original KeyboardEvent
You can access the original KeyboardEvent via detail.originalEvent. This is helpful for checking target.
<script lang="ts">
import type { ShortcutEventDetail } from '@svelte-put/shortcut';
import { shortcut } from '@svelte-put/shortcut';
function onShortcut(event: CustomEvent<ShortcutEventDetail>) {
const keyboardEvent = event.detail.originalEvent;
// be cautious: `keyboardEvent` has already reached window here
keyboardEvent.preventDefault(); // prevent browser default
if ((keyboardEvent.target as HTMLElement)?.tagName === 'INPUT') {
console.log('some input is focused, should skip');
return;
}
// do things
}
</script>
<svelte:window
use:shortcut={{
trigger: {
key: 'k',
modifier: ['ctrl', 'meta'],
},
}}
onshortcut={onShortcut}
/>Be aware that the event listener is placed on the same node the shortcut action is attached to. For example, if you use the action on svelte:window, when a shortcut is triggered from an <input> element, calling stopPropagation or preventDefault on originalEvent might not result in the behavior you would expected. By the time trigger.callback or onshortcut event handler runs, the event has already bubbled up to window.
API References
It is recommended to utilize your language server and intellisense for API exploration. In advanced use cases, however, you can refer to shortcut's type definitions.
Migration Guides
V3 -> V4 (Svelte 5 in Runes mode)
When migrating to V4, you will need to change event directive on:shortcut to standard attribute onshortcut (remove :).
<div use:shortcut on:shortcut></div>
<div use:shortcut onshortcut></div>
Happy making shortcuts! 👨💻