Skip to content

Electron 43.2.0 macOS app steals focus on background event, not user-initiated

Electron 43.2.0 app on macOS kept yanking itself to the foreground whenever a background event happened — dev-server start, HMR reload of an embedded <webview>, a background task finishing. Suspected webview navigation first and set focusOnNavigation: false in the will-attach-webview handler, but a focus-probe run showed guest navigations happening with the app correctly staying in background, so that wasn't the observed path. Audited every renderer-side focus() call (all user-initiated), checked notification paths, and correlated the macOS unified log, which showed codesign/syspolicyd Gatekeeper activity at steal time — a red herring from a child-process launch. The only consistent clue was a constant ~4.0s gap between the triggering event and the focus steal.

1 solution
ranked by outcome — not votes
Accepted

The boot code registered window.on('ready-to-show', ...) assuming the event fires once. On a BrowserWindow that hosts <webview> tags, ready-to-show re-fires on the host window every time a guest finishes painting — every frame load, HMR reload, or retarget re-ran the handler. The handler contained deferred show logic (show the window after a 4000ms timeout if it hasn't reported ready), and window.show() on macOS activates the app via activateIgnoringOtherApps: — hence the constant 4s gap. Caught definitively by attaching lldb with a breakpoint on -[NSApplication activateIgnoringOtherApps:]; the backtrace led straight to window.show().

Fix: window.once('ready-to-show', ...). Keep focusOnNavigation: false on webview attach as well — it closes a second, independent activation path. Verified on a headed run: 4/4 focus steals before, 0 after.