Use createHotkeySequenceRecorder to capture a series of shortcut chords. By default, each step records its physical code: pressing G twice produces ['[KeyG]', '[KeyG]']. Set recordBy: 'key' to follow logical characters instead. Pass the resulting array directly to sequence registration and format each step for display.
TanStack Hotkeys automatically suppresses registered hotkey and sequence callbacks while any recorder is active. You do not need to set enabled from isRecording. Registrations remain available for conflict detection, and recorded keys stay suppressed through repeats and key release.
Recorder options support property getters and functions returning options. Updated callbacks, validation, and recording settings apply during an active session without restarting it. Allow the framework to run its effect or watcher before relying on the update.
This example uses a Save button so plain Enter can be recorded as a step:
<script lang="ts">
import { createHotkeySequenceRecorder, formatForDisplay } from '@tanstack/svelte-hotkeys'
const recorder = createHotkeySequenceRecorder({
commitKeys: 'none',
onRecord: (sequence) => console.log('Register or persist:', sequence),
onReject: ({ message }) => console.log(message),
})
const displayedSteps = $derived(recorder.isRecording ? recorder.steps : recorder.recordedSequence ?? [])
</script>
<button onclick={recorder.startRecording}>Record sequence</button>
<p>{displayedSteps.map((step) => formatForDisplay(step)).join(' → ')}</p>
{#if recorder.isRecording}
<button onclick={recorder.commitRecording}>Save</button>
<button onclick={recorder.cancelRecording}>Cancel</button>
{/if}The recorder exposes isRecording, steps, and recordedSequence as reactive getters. steps contains the current attempt; recordedSequence contains the last committed result. startRecording() begins a new session. commitRecording() saves a nonempty attempt, while cancelRecording() discards it and calls onCancel. stopRecording() resets recorder state without calling onRecord or onCancel.
Escape cancels. Unmodified Backspace/Delete removes the last step; when already empty it stops and calls only onClear. Modifier-only presses, automatic repeats, and IME composition do not append steps. Recorded events and their releases do not trigger application shortcuts.
Set provider defaults through HotkeysProvider with defaultOptions.hotkeySequenceRecorder.
validate(sequence, { events, parsedSequence }) runs at commit. Return true to accept, or false/a message to reject. detectConflicts checks live bindings and sequence prefixes, including physical/logical overlap established by the recorded events. onReject receives feedback; rejected steps remain editable with Backspace.
The shared options and exclusions are described in the hotkey recording guide. The application owns reset, persistence, and any binding being edited; clearing never calls onRecord([]).