Skip to content

fix(hotkeys): Let sequences own the keys after their first step - #184

Merged
KevinVandy merged 2 commits into
mainfrom
fix-116-sequence-consumes-chord
Oct 16, 2026
Merged

KevinVandy merged 2 commits into
mainfrom
fix-116-sequence-consumes-chord

Conversation

@KevinVandy

@KevinVandy KevinVandy commented Oct 16, 2026 •

Copy link
Copy Markdown
Member

Closes #116

  • A key that continues or completes a sequence in progress no longer runs chords for the same key. With a C chord and a G then C sequence registered, pressing G and then C runs only the sequence. C on its own still runs the chord.
  • The manager decides this before any listener for the key press runs. So it holds regardless of registration order, for chords on elements inside the sequence's target, and for capture-phase chords. TargetListeners now tells the manager which listener runs first.
  • The key's automatic repeats and its keyup also skip chords. A missed keyup doesn't block the key's next press.
  • A chord on a sequence's first step still fires right away; nothing is delayed. A sequence doesn't own the key once it has timed out or been disabled, when its target isn't reached, or when it skips the focused input.
  • sequence-ownership.test.ts covers these cases, and a React useHotkey test reproduces the issue. The unified-hotkeys.test.ts case that expected both to fire now expects the chord only on the first G.
  • Adds a "Sequences and chords" section to every framework's sequences guide, and a minor changeset.

Notes

This matches Mousetrap, @github/hotkey, and VS Code, where a pending sequence takes the next key. Those libraries drop a chord on a sequence's first key, or let registration order decide; this PR keeps it firing.

Summary by CodeRabbit

  • Bug Fixes
    • Keys that continue or complete an active sequence no longer also trigger matching chords. Chords can still run on the sequence’s first key.
    • This behavior applies to keyup events, repeated key presses, and capture-phase shortcuts.
  • Documentation
    • Clarified how sequences take priority over overlapping chords across supported frameworks.

A key that continues or completes a sequence in progress no longer runs
chords for the same key, including its repeats and keyup.

Closes #116
@changeset-bot

changeset-bot Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 86e28ce

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 18 packages
Name Type
@tanstack/hotkeys Minor
@tanstack/alpine-hotkeys Patch
@tanstack/angular-hotkeys Patch
@tanstack/ember-hotkeys Patch
@tanstack/hotkeys-devtools Patch
@tanstack/lit-hotkeys Patch
@tanstack/octane-hotkeys Patch
@tanstack/preact-hotkeys Patch
@tanstack/react-hotkeys Patch
@tanstack/solid-hotkeys Patch
@tanstack/svelte-hotkeys Patch
@tanstack/vue-hotkeys Patch
@tanstack/angular-hotkeys-devtools Patch
@tanstack/preact-hotkeys-devtools Patch
@tanstack/react-hotkeys-devtools Patch
@tanstack/solid-hotkeys-devtools Patch
@tanstack/svelte-hotkeys-devtools Patch
@tanstack/vue-hotkeys-devtools Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai

coderabbitai Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository: TanStack/hotkeys/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 5776e886-0f4b-4301-a2fe-35f7079e2a01
📥 Commits

Reviewing files that changed from the base of the PR and between d3f54dd and 86e28ce.

⛔ Files ignored due to path filters: 15
  • docs/reference/classes/HotkeyManager.md is excluded by !docs/**/reference/**
  • docs/reference/functions/getHotkeyManager.md is excluded by !docs/**/reference/**
  • docs/reference/functions/toHotkeyRegistrationView.md is excluded by !docs/**/reference/**
  • docs/reference/interfaces/HotkeyChordOptions.md is excluded by !docs/**/reference/**
  • docs/reference/interfaces/HotkeyChordRegistration.md is excluded by !docs/**/reference/**
  • docs/reference/interfaces/HotkeyChordRegistrationView.md is excluded by !docs/**/reference/**
  • docs/reference/interfaces/HotkeyOptions.md is excluded by !docs/**/reference/**
  • docs/reference/interfaces/HotkeyRegistrationHandle.md is excluded by !docs/**/reference/**
  • docs/reference/interfaces/HotkeySequenceOptions.md is excluded by !docs/**/reference/**
  • docs/reference/interfaces/HotkeySequenceRegistration.md is excluded by !docs/**/reference/**
  • docs/reference/interfaces/HotkeySequenceRegistrationView.md is excluded by !docs/**/reference/**
  • docs/reference/type-aliases/HotkeyOptionsFor.md is excluded by !docs/**/reference/**
  • docs/reference/type-aliases/HotkeyRegistration.md is excluded by !docs/**/reference/**
  • docs/reference/type-aliases/HotkeyRegistrationView.md is excluded by !docs/**/reference/**
  • docs/reference/type-aliases/Target.md is excluded by !docs/**/reference/**
📒 Files selected for processing: 16
  • .changeset/sequence-owns-keys.md
  • docs/framework/alpine/guides/sequences.md
  • docs/framework/angular/guides/sequences.md
  • docs/framework/ember/guides/sequences.md
  • docs/framework/lit/guides/sequences.md
  • docs/framework/octane/guides/sequences.md
  • docs/framework/preact/guides/sequences.md
  • docs/framework/react/guides/sequences.md
  • docs/framework/solid/guides/sequences.md
  • docs/framework/svelte/guides/sequences.md
  • docs/framework/vue/guides/sequences.md
  • packages/hotkeys/src/_target-listeners.ts
  • packages/hotkeys/src/hotkey-manager.ts
  • packages/hotkeys/tests/sequence-ownership.test.ts
  • packages/hotkeys/tests/unified-hotkeys.test.ts
  • packages/react-hotkeys/tests/useHotkey.test.tsx

Included review availability: This review used your included allowance. Your plan provides up to 4 included reviews per hour; 3 remain after this review.

📝 Walkthrough

HotkeyManager now tracks whether keyboard events continue active sequences. Matching chords are skipped for sequence-owned events, while chords remain eligible on a sequence’s first step. Tests and framework guides cover ownership and its eligibility conditions.

Changes: Sequence and chord key ownership

Layer / File(s) Summary
Track sequence-owned events
packages/hotkeys/src/_target-listeners.ts, packages/hotkeys/src/hotkey-manager.ts
Target listener dispatch now identifies the first processing group. HotkeyManager checks whether an event continues an active sequence, tracks owned physical keys across repeats and keyup, and skips matching chord processing for owned events.
Validate and document ownership
packages/hotkeys/tests/*, packages/react-hotkeys/tests/useHotkey.test.tsx, docs/framework/*/guides/sequences.md, .changeset/sequence-owns-keys.md
Tests cover continuation and completion keys, first-step chords, and ownership conditions. Framework guides and the changeset describe sequence and chord behavior.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix · Severity of issue fixed: Medium

Sequence Diagram(s)

sequenceDiagram
  participant TargetListeners
  participant HotkeyManager
  participant ActiveSequences
  participant ChordProcessing
  TargetListeners->>HotkeyManager: Dispatch keyboard event
  HotkeyManager->>ActiveSequences: Check sequence continuation
  ActiveSequences-->>HotkeyManager: Return ownership result
  HotkeyManager->>ChordProcessing: Skip chord processing when sequence owns event
Loading
Merge Risk: ⚪ Minimal · up to 86e28

The changed sequence and chord behavior has no identified merge-blocking issue; it is ready for normal checks.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 2 functions across 5 files. (11 skipped: 1… Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Title check Passed The title clearly and concisely describes the primary change: sequences own keys after their first step.
Description check Passed The description provides a detailed summary of the behavior change, affected cases, tests, documentation updates, and changeset. It does not reproduce the template headings or checklist, but the requi…
Linked Issues check Passed Issue [#116] requires the single-key callback to stop firing while an active sequence matches. HotkeyManager now marks continuing sequence events before listener dispatch and suppresses matching cho…
Out of Scope Changes check Passed The changes stay within issue [#116]. The manager change implements sequence ownership. The tests verify the reported behavior and related event-handling cases. The framework guide updates and the min…
Full details: Description check

Explanation

The description provides a detailed summary of the behavior change, affected cases, tests, documentation updates, and changeset. It does not reproduce the template headings or checklist, but the required change and release-impact information are substantially covered.

Full details: Linked Issues check

Explanation

Issue [#116] requires the single-key callback to stop firing while an active sequence matches. HotkeyManager now marks continuing sequence events before listener dispatch and suppresses matching chords. The implementation covers the G then C case, repeats, and keyup. sequence-ownership.test.ts, the React useHotkey regression test, and the updated unified test provide automated coverage.

Full details: Out of Scope Changes check

Explanation

The changes stay within issue [#116]. The manager change implements sequence ownership. The tests verify the reported behavior and related event-handling cases. The framework guide updates and the minor changeset document the implemented behavior. No unrelated product behavior is identified.

Full details: Docstring Coverage

Explanation

Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 2 functions across 5 files. (11 skipped: 11 unsupported.)

Resolution

Write docstrings for the functions missing them to satisfy the coverage threshold.

  • Fix all pre-merge checks with AI
✨ Finishing Touches: 💡 1
📝 Generate docstrings: 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

A rabbit taps G, then C,
The sequence runs quietly.
First-step chords still get their turn,
While owned keys take the sequence’s course.
Repeats and keyups follow through,
Then hops away beneath the moon.

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown
Contributor

🚀 Changeset Version Preview

1 package(s) bumped directly, 17 bumped as dependents.

🟥 Major bumps

Package Version Reason
@tanstack/hotkeys-devtools 1.3.4 → 2.0.0 Dependent

🟨 Minor bumps

Package Version Reason
@tanstack/hotkeys 0.14.0 → 0.15.0 Changeset

🟩 Patch bumps

Package Version Reason
@tanstack/alpine-hotkeys 0.3.3 → 0.3.4 Dependent
@tanstack/angular-hotkeys 0.14.3 → 0.14.4 Dependent
@tanstack/angular-hotkeys-devtools 0.2.5 → 0.2.6 Dependent
@tanstack/ember-hotkeys 0.3.3 → 0.3.4 Dependent
@tanstack/lit-hotkeys 0.15.3 → 0.15.4 Dependent
@tanstack/octane-hotkeys 0.4.3 → 0.4.4 Dependent
@tanstack/preact-hotkeys 0.14.3 → 0.14.4 Dependent
@tanstack/preact-hotkeys-devtools 0.10.5 → 0.10.6 Dependent
@tanstack/react-hotkeys 0.14.3 → 0.14.4 Dependent
@tanstack/react-hotkeys-devtools 0.10.5 → 0.10.6 Dependent
@tanstack/solid-hotkeys 0.14.3 → 0.14.4 Dependent
@tanstack/solid-hotkeys-devtools 0.10.5 → 0.10.6 Dependent
@tanstack/svelte-hotkeys 0.14.3 → 0.14.4 Dependent
@tanstack/svelte-hotkeys-devtools 0.2.5 → 0.2.6 Dependent
@tanstack/vue-hotkeys 0.14.3 → 0.14.4 Dependent
@tanstack/vue-hotkeys-devtools 0.10.5 → 0.10.6 Dependent

@pkg-pr-new

pkg-pr-new Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

Open in StackBlitz

@tanstack/alpine-hotkeys

npm i https://pkg.pr.new/@tanstack/alpine-hotkeys@184

@tanstack/angular-hotkeys

npm i https://pkg.pr.new/@tanstack/angular-hotkeys@184

@tanstack/angular-hotkeys-devtools

npm i https://pkg.pr.new/@tanstack/angular-hotkeys-devtools@184

@tanstack/ember-hotkeys

npm i https://pkg.pr.new/@tanstack/ember-hotkeys@184

@tanstack/hotkeys

npm i https://pkg.pr.new/@tanstack/hotkeys@184

@tanstack/hotkeys-devtools

npm i https://pkg.pr.new/@tanstack/hotkeys-devtools@184

@tanstack/lit-hotkeys

npm i https://pkg.pr.new/@tanstack/lit-hotkeys@184

@tanstack/octane-hotkeys

npm i https://pkg.pr.new/@tanstack/octane-hotkeys@184

@tanstack/preact-hotkeys

npm i https://pkg.pr.new/@tanstack/preact-hotkeys@184

@tanstack/preact-hotkeys-devtools

npm i https://pkg.pr.new/@tanstack/preact-hotkeys-devtools@184

@tanstack/react-hotkeys

npm i https://pkg.pr.new/@tanstack/react-hotkeys@184

@tanstack/react-hotkeys-devtools

npm i https://pkg.pr.new/@tanstack/react-hotkeys-devtools@184

@tanstack/solid-hotkeys

npm i https://pkg.pr.new/@tanstack/solid-hotkeys@184

@tanstack/solid-hotkeys-devtools

npm i https://pkg.pr.new/@tanstack/solid-hotkeys-devtools@184

@tanstack/svelte-hotkeys

npm i https://pkg.pr.new/@tanstack/svelte-hotkeys@184

@tanstack/svelte-hotkeys-devtools

npm i https://pkg.pr.new/@tanstack/svelte-hotkeys-devtools@184

@tanstack/vue-hotkeys

npm i https://pkg.pr.new/@tanstack/vue-hotkeys@184

@tanstack/vue-hotkeys-devtools

npm i https://pkg.pr.new/@tanstack/vue-hotkeys-devtools@184

commit: 86e28ce

@KevinVandy
KevinVandy merged commit d7a7e81 into main Oct 16, 2026
9 checks passed
@KevinVandy
KevinVandy deleted the fix-116-sequence-consumes-chord branch October 16, 2026 15:46
@github-actions github-actions Bot mentioned this pull request Oct 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

useHotkey callback fire during active useHotkeySequence matching

1 participant