Skip to content

fix(devtools): claim the inspect click in the capture phase - #516

Open
thedv91 wants to merge 1 commit into
TanStack:mainfrom
thedv91:feat-inspect-click-capture-phase
Open

fix(devtools): claim the inspect click in the capture phase#516
thedv91 wants to merge 1 commit into
TanStack:mainfrom
thedv91:feat-inspect-click-capture-phase

Conversation

@thedv91

@thedv91 thedv91 commented Aug 22, 2026

Copy link
Copy Markdown

🎯 Changes

Holding the inspect hotkey and clicking an element:

Before After
A button with an onClick source opens, and the button fires too source opens, the button stays untouched
Anything inside a modal or dropdown that stops click propagation nothing at all — no source, and the button fires source opens, the button stays untouched

SourceInspector listened on document in the bubble phase. By then React has already dispatched its synthetic onClick and a router link has already navigated, and preventDefault() cannot undo either — it only cancels the browser's own default action. The second row is the sharper one: an ancestor calling stopPropagation(), which is every overlay that closes on an outside click, stops the event before it reaches document, so the handler never ran and an inspect click inside a modal silently did nothing.

{ capture: true } fixes both, and costs the page nothing: the handler returns immediately unless the hotkey is held over an element carrying data-tsd-source, and it already performs the open-in-editor or copy itself rather than relying on anything downstream.

Still open, and out of scope here: mousedown/pointerdown are untouched, so a drag or focus wired to those still starts on an inspect click.

Verificationexamples/react/basic, with a throwaway component holding a plain <button onClick> and a button inside a <div> whose native click listener calls stopPropagation(). On main, an inspect click on the plain button copied …/inspect-click-repro.tsx:35:7 and took its counter 1 → 2; the same click inside the modal took that counter 1 → 2 and copied nothing. With this change both copied their path and neither counter moved, while ordinary clicks without the hotkey still increment both. source-inspector.test.tsx pins the modal case; it fails on main.

✅ Checklist

  • I have followed the steps in the Contributing guide.
  • I have tested this code locally with pnpm test:pr.

🚀 Release Impact

  • This change affects published code, and I have generated a changeset.

Summary by CodeRabbit

  • Bug Fixes
    • Source inspection now works reliably inside modals, dropdowns, and other elements that stop click propagation.
    • Inspected elements no longer activate unintentionally when opening their source.
    • Ordinary clicks continue to behave normally when inspection mode is inactive.

@coderabbitai

coderabbitai Bot commented Aug 22, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 3f853594-c275-487e-98bf-a815abfdcad0

📥 Commits

Reviewing files that changed from the base of the PR and between 566d39b and de3c8dd.

📒 Files selected for processing (3)
  • .changeset/inspect-click-capture-phase.md
  • packages/devtools/src/components/source-inspector.test.tsx
  • packages/devtools/src/components/source-inspector.tsx

Included review availability: Your plan provides up to 2 included reviews per hour; 1 remains after this review.


📝 Walkthrough

Walkthrough

The source inspector now handles armed clicks during the document capture phase. Tests cover propagation-stopping ancestors and ordinary clicks without the inspection hotkey. A patch changeset documents the update.

Changes

Source inspection click handling

Layer / File(s) Summary
Capture-phase inspection handling
packages/devtools/src/components/source-inspector.tsx, packages/devtools/src/components/source-inspector.test.tsx, .changeset/inspect-click-capture-phase.md
SourceInspector uses a named document capture handler for inspection clicks. Tests verify source activation through propagation-stopping ancestors and preserve unarmed clicks. A patch changeset records the behavior.
Estimated code review effort: 2 (Simple) ~10 minutes

Merge Risk: ⚪ Minimal · up to de3c8

The change prevents inspect clicks from triggering underlying button actions or being swallowed by stopping ancestors, while preserving ordinary clicks. No actionable merge-blocking risk remains beyond normal checks and review.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant document
  participant SourceInspector
  participant Ancestor
  User->>document: Click an inspected element
  document->>SourceInspector: Invoke onInspectClick during capture
  SourceInspector->>SourceInspector: Open or copy the source
  document->>Ancestor: Continue dispatch for an unarmed click
  Ancestor-->>User: Handle the ordinary click
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the primary change: handling inspect clicks during the capture phase.
Description check ✅ Passed The description explains the motivation, behavior, verification, scope, checklist completion, and generated changeset.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 2 files. (1 skipped: 1 unsupported.)
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

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

The source inspector listened for clicks in the bubble phase, so by the time
it ran the page had already acted on the click: React had dispatched its
synthetic onClick, a router link had navigated. preventDefault() cancels only
the browser's own default action, so none of that could be undone.

Worse, any ancestor calling stopPropagation() -- a modal or dropdown that
closes on an outside click -- stopped the event before it reached document,
so inspecting inside one silently did nothing at all.

Claiming the click in the capture phase fixes both. It costs the page nothing:
the handler returns immediately unless the inspect hotkey is held over an
element carrying data-tsd-source, and it already performs the open-in-editor
or copy itself.
@thedv91
thedv91 force-pushed the feat-inspect-click-capture-phase branch from de3c8dd to 153a720 Compare August 22, 2026 03:43
@nx-cloud

nx-cloud Bot commented Aug 24, 2026

Copy link
Copy Markdown

🤖 Nx Cloud AI Fix Eligible

An automatically generated fix could have helped fix failing tasks for this run, but Self-healing CI is disabled for this workspace. Visit workspace settings to enable it and get automatic fixes in future runs.

To disable these notifications, a workspace admin can disable them in workspace settings.


View your CI Pipeline Execution ↗ for commit 153a720

Command Status Duration Result
nx affected --targets=test:eslint,test:sherif,t... ❌ Failed 2m 21s View ↗
nx run-many --target=test:e2e --parallel=1 --pr... ✅ Succeeded 1m 16s View ↗
nx run-many --targets=build --exclude=examples/... ✅ Succeeded 34s View ↗

☁️ Nx Cloud last updated this comment at 2026-08-24 16:30:52 UTC

@pkg-pr-new

pkg-pr-new Bot commented Aug 24, 2026

Copy link
Copy Markdown
More templates

@tanstack/angular-devtools

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

@tanstack/devtools

npm i https://pkg.pr.new/@tanstack/devtools@516

@tanstack/devtools-a11y

npm i https://pkg.pr.new/@tanstack/devtools-a11y@516

@tanstack/devtools-bundler-core

npm i https://pkg.pr.new/@tanstack/devtools-bundler-core@516

@tanstack/devtools-client

npm i https://pkg.pr.new/@tanstack/devtools-client@516

@tanstack/devtools-rspack

npm i https://pkg.pr.new/@tanstack/devtools-rspack@516

@tanstack/devtools-ui

npm i https://pkg.pr.new/@tanstack/devtools-ui@516

@tanstack/devtools-utils

npm i https://pkg.pr.new/@tanstack/devtools-utils@516

@tanstack/devtools-vite

npm i https://pkg.pr.new/@tanstack/devtools-vite@516

@tanstack/devtools-event-bus

npm i https://pkg.pr.new/@tanstack/devtools-event-bus@516

@tanstack/devtools-event-client

npm i https://pkg.pr.new/@tanstack/devtools-event-client@516

@tanstack/preact-devtools

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

@tanstack/react-devtools

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

@tanstack/solid-devtools

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

@tanstack/svelte-devtools

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

@tanstack/vue-devtools

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

commit: 153a720

@thedv91

thedv91 commented Aug 24, 2026

Copy link
Copy Markdown
Author

The test:types failure doesn't look like it's coming from this branch.

@tanstack/devtools:test:types resolves @tanstack/devtools-ui through its built dist, so if that dist isn't in place yet, tsc dies in a couple of seconds with a wall of TS2307:

src/context/devtools-store.ts(4,44): error TS2307: Cannot find module '@tanstack/devtools-ui' or its corresponding type declarations.

That matches the shape of the failure here — 3s, only test:types, while test:lib, test:eslint and build all passed on the same tree. devtools-ui:build was a 0s remote cache hit in that run, and with NX_PARALLEL: 3 my guess is tsc started before the restore finished. #517 had the same cache state and passed.

I pushed the identical tree through CI twice on my fork, once with Nx Cloud off and once on, and test:types passed both times; same locally on Node 24.8.0 with TS 5.9.3. The real error text only goes to Nx Cloud, which I can't open — could someone re-run the job?

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.

2 participants