Skip to content

fix: disable refetchOnWindowFocus globally to prevent modal close on tab switch - #4853

Open
ANSUJKMEHER wants to merge 2 commits into
Dokploy:canaryfrom
ANSUJKMEHER:fix-4851-modal-blur-fix
Open

fix: disable refetchOnWindowFocus globally to prevent modal close on tab switch#4853
ANSUJKMEHER wants to merge 2 commits into
Dokploy:canaryfrom
ANSUJKMEHER:fix-4851-modal-blur-fix

Conversation

@ANSUJKMEHER

@ANSUJKMEHER ANSUJKMEHER commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Summary

Disables TanStack Query's refetchOnWindowFocus globally to prevent dialog/modal forms from closing and losing data when the browser tab or window regains focus.

Fixes #4851
Fixes #4907

Root Cause

TanStack Query's refetchOnWindowFocus defaults to true. When the user switches away from Dokploy and returns:

  1. The focus event fires on the window
  2. TanStack Query refetches all active queries (e.g., project.one, environment.one, project.all)
  3. On remote servers with network latency, the refetch response returns a new data reference (timestamps/status may differ)
  4. React re-renders the component tree
  5. Dialog components remount, resetting their useState(false)modal closes, form data lost

This is timing/latency dependent — it reproduces reliably on remote servers but rarely on localhost (where queries complete instantly and structuralSharing returns the same reference).

Changes

apps/dokploy/utils/api.ts

  • Added queryClientConfig.defaultOptions.queries.refetchOnWindowFocus: false to the global tRPC config
  • This is consistent with 14+ individual queries in the codebase that already set refetchOnWindowFocus: false per-query (e.g., in use-whitelabeling.ts, dashboard-layout.tsx, side.tsx, handle-destinations.tsx, etc.)

apps/dokploy/components/ui/dialog.tsx

  • Reverted a previously added onFocusOutside handler that was redundant — Radix UI's DialogContentModal already calls event.preventDefault() on onFocusOutside internally for modal dialogs (source)

Testing

  • Verified that the refetchOnWindowFocus: false config is correctly accepted by createTRPCNext's queryClientConfig option
  • Traced through Radix UI source code (@radix-ui/react-dialog, @radix-ui/react-dismissable-layer, @radix-ui/primitive) to confirm the onFocusOutside handler was redundant

@ANSUJKMEHER
ANSUJKMEHER requested a review from Siumauricio as a code owner July 19, 2026 12:27
@dosubot dosubot Bot added size:XS This PR changes 0-9 lines, ignoring generated files. bug Something isn't working size:S This PR changes 10-29 lines, ignoring generated files. and removed size:XS This PR changes 0-9 lines, ignoring generated files. labels Jul 19, 2026
@ANSUJKMEHER ANSUJKMEHER changed the title fix: prevent dialog close on window blur and tab switch fix: disable refetchOnWindowFocus globally to prevent modal close on tab switch Jul 25, 2026
@ANSUJKMEHER

Copy link
Copy Markdown
Contributor Author

Updated the PR with the correct root cause fix:

Reverted the onFocusOutside handler — Radix UI already handles this for modal dialogs internally, so it was redundant.
Added refetchOnWindowFocus: false globally in api.ts — this is the actual root cause. TanStack Query's default refetchOnWindowFocus: true refetches all active queries on tab return, which on remote servers (with network latency) re-renders the component tree and resets dialog useState(false), closing the modal.
This is consistent with the 14+ queries in the codebase that already set refetchOnWindowFocus: false individually.

Also fixes #4907 (duplicate).

This fix addresses the issue where any modal (such as Create Database) closes immediately when the browser tab/window loses focus (blur event) or during Alt+Tab, causing users to lose all partially filled form data.

Root cause: Radix UI's DismissableLayer relies on document-level focus tracking via the useFocusOutside hook. When a window blur occurs, the active input blurred event triggers onBlurCapture which sets focus-in-react-tree tracker to false. When focus is recaptured, a focusin event triggers onFocusOutside. Because DialogContent did not handle this event, it defaulted to closing the dialog.

Solution: We intercept onFocusOutside inside DialogContent and invoke event.preventDefault(). This stops the event propagation to the DismissableLayer's close handler, keeping the modal open when switching windows/tabs while preserving all existing modal features (like Escape key closure, clicking outside overlay, and standard focus trapping).

Fixes Dokploy#4851
…tab switch

TanStack Query's refetchOnWindowFocus (default: true) causes all active
queries to refetch when the browser tab regains focus. On remote servers
with network latency, this re-renders the component tree and resets
dialog useState(false), closing modals and losing form data.

This sets refetchOnWindowFocus: false as the global default in the tRPC
QueryClient config, consistent with the 14+ individual queries in the
codebase that already disable it.

Also reverts the redundant onFocusOutside handler in dialog.tsx — Radix
UI's DialogContentModal already calls event.preventDefault() on
onFocusOutside internally for modal dialogs.

Fixes Dokploy#4851
Fixes Dokploy#4907
@ANSUJKMEHER
ANSUJKMEHER force-pushed the fix-4851-modal-blur-fix branch from d479d31 to 10050b8 Compare July 29, 2026 09:28
@ANSUJKMEHER

Copy link
Copy Markdown
Contributor Author

Hi @Siumauricio , just following up on this PR.

I updated it based on my investigation and narrowed the fix down to disabling refetchOnWindowFocus globally, which addresses the modal-closing issue. I also removed the redundant onFocusOutside change after confirming Radix already handles it internally.

All checks are passing now. If you have a chance, I'd really appreciate a review. Thanks!

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

Labels

bug Something isn't working size:S This PR changes 10-29 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

new database window closes if not focused Modal closes when switching browser window/tab while filling form

1 participant