Use useHotkeySequenceRecorder to record an ordered sequence of chords. Recording defaults to physical codes, such as ['[KeyG]', 'Alt+[KeyS]']. Use recordBy: 'key' for logical characters. Pass the saved array directly to useHotkeySequence.
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.
import Component from '@glimmer/component'
import { tracked } from '@glimmer/tracking'
import { on } from '@ember/modifier'
import { useHotkeySequence, useHotkeySequenceRecorder, formatForDisplay } from '@tanstack/ember-hotkeys'
import type { HotkeySequence } from '@tanstack/ember-hotkeys'
export default class SequenceSettings extends Component {
@tracked binding: HotkeySequence = ['G', 'G']
recorder = useHotkeySequenceRecorder(this, {
onRecord: (sequence) => { this.binding = sequence },
})
goToTop = () => console.log('Go to top')
get preview() { return this.recorder.steps.map((step) => formatForDisplay(step)).join(' → ') }
<template>
{{useHotkeySequence this.binding this.goToTop}}
<button type="button" {{on 'click' this.recorder.startRecording}}>Record sequence</button>
{{#if this.recorder.isRecording}}
<p>{{this.preview}}</p>
<button type="button" {{on 'click' this.recorder.commitRecording}}>Save</button>
<button type="button" {{on 'click' this.recorder.cancelRecording}}>Cancel</button>
{{/if}}
</template>
}Press and release each chord, then press Enter or click Save. Cancellation leaves the saved binding unchanged.
| Property | Type | Meaning |
|---|---|---|
| isRecording | boolean | Whether a session is active. |
| steps | HotkeySequence | Chords captured in the current session. |
| recordedSequence | HotkeySequence | null | The last committed sequence. |
| startRecording | () => void | Start a new session. |
| stopRecording | () => void | Stop without calling onRecord or onCancel. |
| cancelRecording | () => void | Discard the session and call onCancel. |
| commitRecording | () => void | Commit current steps; do nothing if empty. |
Read state through the recorder object. Destructuring its reactive getters once captures a snapshot.
Pass defaults to createHotkeysScope. The scope accepts hotkey, hotkeySequence, hotkeyRecorder, and hotkeySequenceRecorder options. Use the returned contextual helpers and recorder factories. Pass the scope through component arguments to share it with descendants; helpers and recorders still clean up with their own owners. Pass a getter for tracked defaults. Call-specific options override scope defaults, and per-definition options override common options. Omitted options use the core defaults. See shared defaults for a complete example. Options getters are read during recording and commit, so policy and callback changes also apply to active sessions.
The default is true, so normal typing in inputs, textareas, selects, and contentEditable elements passes through. Escape still cancels. Set ignoreInputs: false to record in a focused input.
validate(sequence, { events, parsedSequence }) runs when committing and returns true, false, or a rejection message. detectConflicts checks single bindings and sequence prefixes. A rejected commit keeps the session active and the steps intact, so the user can edit them with Backspace.
The recorder supports the same detectConflicts, validate, and onReject options as the single-hotkey recorder. Use live registration IDs to exclude the binding being edited. Physical/logical overlap is based on the captured events, not a guessed keyboard layout.
| Input | Behavior |
|---|---|
| Valid chord | Append to steps and continue listening. |
| Unmodified Enter with default commit settings and nonempty steps | Commit and call onRecord. |
| Escape | Cancel and call onCancel. |
| Unmodified Backspace or Delete with nonempty steps | Remove the last step without committing. |
| Unmodified Backspace or Delete with empty steps | Stop and call only onClear. |
| Modifier-only press, repeat, or IME composition | Do not append a step. |
Recorded chords use portable Mod. Recording events, commit keys, and their releases are isolated from application hotkeys and sequences. Code mode rejects AltGraph character entry; key mode preserves the produced character without synthetic Control/Alt.
Ember owns the core Store subscription and recorder through the supplied owner. Destruction cancels active recording and releases listeners.
See the useHotkeySequenceRecorder example for editable sequence settings and the kitchen sink for manual commit, idle timeout, validation, and conflict feedback.