@svelte-put/shortcut
Installation
npm install --save-dev @svelte-put/shortcut@^3.0.0
pnpm add -D @svelte-put/shortcut@^3.0.0
yarn add -D @svelte-put/shortcut@^3.0.0
Quick Start
The minimal example below shows how to register a global shortcut for Ctrl + K
(Cmd + K
on macOS) and log the attached node and the original trigger config.
<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 modifier strings (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 modifier strings 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 modifier strings 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 on:shortcut
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',
},
}}
on:shortcut={handleShortcuts}
/>
trigger.id
is specified in the handler-custom-event.svelte
example to conveniently help identify the trigger in the on:shortcut
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 on:shortcut
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',
}}
/>
KeyboardEvent
Original 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'],
},
}}
on:shortcut={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
, and trigger a matching shortcut 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 on:shortcut
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.
Happy making shortcuts! 👨💻