Skip to content

fix(dom): support drag-and-drop in detached window contexts (window.open popups) - #2121

Open
singarp26 wants to merge 3 commits into
clauderic:mainfrom
singarp26:fix/cross-window-drag-dom
Open

singarp26 wants to merge 3 commits into
clauderic:mainfrom
singarp26:fix/cross-window-drag-dom

Conversation

@singarp26

Copy link
Copy Markdown

Problem: getDocuments misses window.open popup documents; Scheduler freezes when the main tab is backgrounded during a popup drag
Approach: opt-in global registry globalThis.dndKitDocuments: Set — consumers register popup documents on open and deregister on close; zero impact when the registry is absent
Affected files: packages/dom/src/utilities/... (wherever getDocuments and Scheduler live in the source tree)
Include a minimal reproduction: open a window.open popup, mount a DragDropProvider in it, try to drag — events are lost

@changeset-bot

changeset-bot Bot commented Aug 6, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 1b8713a

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

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

@clauderic clauderic added dom DOM package enhancement New feature or request labels Aug 9, 2026

@clauderic clauderic left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

Adds support for drag-and-drop across window.open() popup documents by (1) having getDocuments() include any documents the host app has registered on a globalThis.__dndKitDocuments__ set, and (2) rerouting scheduler's requestAnimationFrame to a visible popup window when the main document is hidden.

Thanks for taking a run at #2100 — cross-window drag is a genuinely hard gap and it's great to see someone tackling it.

Feedback

Blocking issues

  • packages/dom/src/utilities/execution-context/getDocuments.ts:47 and packages/dom/src/utilities/scheduling/scheduler.ts:39the integration point is an undocumented global. globalThis.__dndKitDocuments__ is a mutable global that the host app is expected to populate, with no exported registration function, no type surface, and no lifecycle. This doesn't fit the library's architecture: cross-cutting behaviour like this belongs on the manager (a DragDropManagerInput option) or in a Plugin that owns registration and tears down in destroy(). As written there's also no way to unregister a document, so a closed popup leaks into the set indefinitely.

  • packages/dom/src/utilities/scheduling/scheduler.ts:39-56this can permanently wedge the scheduler. Scheduler.schedule() sets this.pending = true and only clears it inside flush. If the popup window is closed (or its rAF is throttled) between the win.requestAnimationFrame(callback) call and the frame firing, flush never runs: pending stays true, every subsequent schedule() call silently queues a task that never executes, and every returned promise never resolves. Since scheduler is a module-level singleton used across @dnd-kit/dom, that would freeze the whole library for the page. There's no fallback timer and no window.closed check.

  • packages/dom/src/utilities/scheduling/scheduler.ts:41the document.hidden condition is too broad. document.hidden is true for any backgrounded tab, not only when a popup has focus. As soon as the user switches to another tab, scheduling is diverted into a popup window regardless of whether a cross-window drag is in progress.

  • Missing changeset. This modifies files under packages/dom/src/, so it needs a .changeset/*.md with '@dnd-kit/dom': patch (or minor, since this is really new functionality rather than a bug fix).

  • any casts. Both new blocks use (globalThis as any).__dndKitDocuments__. The repo's convention is full type safety without any; the accompanying dndKitDocuments.d.ts declare global should make the cast unnecessary — but that file isn't imported anywhere, so it's unclear whether the ambient declaration is actually picked up by the build. Worth verifying.

Suggestions

  • packages/dom/src/utilities/execution-context/dndKitDocuments.d.ts:4 — file is missing a trailing newline.
  • packages/dom/src/utilities/execution-context/getDocuments.ts:47 — indentation is off by one space ( // Traverse...), and the comment says "registered by the host app" without explaining where that registration is supposed to happen.
  • getDocuments() is recursive with a shared seen set, so the popup-document block runs at every level of the recursion. It works because of the dedupe, but it means popups get appended from whichever frame reaches it first. Hoisting it to the top-level call would be clearer. Related: the popup documents are added directly rather than passed back through getDocuments(popupDoc, seen), so their own iframes are never discovered.
  • No tests. A regression test would be hard for real popups, but the getDocuments merge behaviour is testable in isolation with bun:test.
  • No JSDoc on the new behaviour, and getDocuments's existing doc comment still says it returns only the current document plus same-origin parents and children.

Changeset

  • Status: missing. Needs '@dnd-kit/dom'minor if this is treated as a new capability, patch if scoped as a fix.

Overall

The underlying problem is real and worth solving, but the current shape — a magic global plus a global rAF override — has failure modes that reach well beyond the cross-window case. We'd suggest reworking this as an explicit, disposable registration API (manager option or plugin) and confining the scheduler change to an active cross-window drag, with a fallback so the scheduler can never deadlock. Thanks again for digging into this.


[claude-review]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dom DOM package enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants