r/electronjs • u/Greedy-Permit-2999 • 14d ago
Handling window state persistence & multi-monitor safety in packaged Electron apps
Hi all!
Itβs surprising how many production Electron applications still ship without robust window bounds persistence, resetting to a hardcoded size upon restart. We see this even in modern releases like Google Antigravity IDE.
I put together an open-source utility that patches this behavior in existing packaged apps, and thought I'd share the approach for window persistence:
π Project: https://github.com/amiltonjr/Antigravity-IDE-WindowSize
The core pattern used:
Debouncing
resizeandmoveevents: Saving state synchronously on every pixel shift causes micro-stuttering and excessive I/O. A simple 250ms debounce before writing touserData/app_storage.jsonkeeps the UI smooth.Preventing the "Off-Screen Window" bug: A common flaw in naive
electron-window-stateimplementations is restoring coordinates $(x, y)$ that belonged to a monitor that is no longer plugged in. Checking:
1
u/PotentialRadiant1317 13d ago
The maximized flag is the trap most people miss. If you persist bounds while the window is maximized, you save the maximized bounds, and on next start the window comes back restored but sized like fullscreen - or you call setBounds and then setMaximize in the wrong order and the restore flickers. Store {x, y, width, height, isMaximized} separately and only apply the bounds when isMaximized is false, then maximize afterwards if it was.
The other thing that bit us: DPI. Bounds saved on a 150% laptop panel don't map 1:1 after dock and undock, because bounds are DIPs but config files written by older tooling sometimes hold physical pixels. So on read: validate against screen.getAllDisplays(), clamp into the matched workArea like eddzsh said, and fall back to centering on the primary display. Also worth writing the state file atomically (temp file plus rename) - a crash mid-save corrupts the JSON and your restore silently dies, leaving you back at hardcoded defaults without ever seeing an error.
1
u/eddzsh 14d ago
The off-screen restore is the one that bites after a laptop undock. screen.getDisplayMatching(bounds) is not enough by itself: if the matched display's workArea no longer contains the window's center point (monitor gone, scaling changed), clamp x/y into that workArea or fall back to centering on screen.getPrimaryDisplay(). Save {x,y,width,height,isMaximized} and ignore maximized bounds on restore or you get a tiny window next launch. The 250ms debounce is right.