electron-osx-restorable-state
v0.2.0
Published
macOS State Restoration for Electron — automatically save and restore window position, Space, and custom data
Maintainers
Readme
electron-osx-restorable-state
macOS State Restoration for Electron — automatically save and restore window position, Space (virtual desktop), and custom data via the OS-native restoration mechanism.
Why?
Electron does not participate in macOS State Restoration (electron/electron#37494). Windows always open on the current Space and lose their previous frame. This package hooks into AppKit's native restoration cycle so macOS handles everything automatically — no manual save/load needed.
Install
npm install electron-osx-restorable-stateRequires Xcode Command Line Tools for the native addon build.
Usage
const { app, BrowserWindow } = require('electron');
require('electron-osx-restorable-state');
app.on('restore-window', (identifier, state, done) => {
try {
if (identifier) {
// Restore a window from the previous session
const win = new BrowserWindow({ show: false });
win.restorableIdentifier = identifier;
// state contains the custom data saved via restorableState
win.show();
} else {
// No windows to restore — create a default window
const win = new BrowserWindow({ width: 800, height: 600 });
win.restorableIdentifier = 'main-window';
win.restorableState = { openTabs: ['tab1', 'tab2'] };
}
} finally {
done();
}
});Note:
- State Restoration requires a packaged app (with a stable bundle identifier). It does not work when running with
electron .during development.- macOS has separate restoration flows: restart/login and app-only quit/relaunch. Restart/login reopening is controlled by the system checkbox "Reopen windows when logging back in" in restart/shutdown dialogs.
- App-only quit/relaunch behavior depends on app state and Desktop & Dock settings. For reliable local testing, turn off "Close windows when quitting an application".
- Space/Desktop placement is managed by Mission Control (for example, auto-rearrange Spaces and app-switch Space jumping). This package primarily guarantees window restoration and custom state restoration.
API
app.on('restore-window', (identifier, state, done) => ...) (macOS only)
Emitted during ready for window restoration.
- When macOS has windows to restore: fires once per window with
identifierset andstatecontaining custom data previously saved viarestorableState. - When there are no windows to restore (first launch, etc.): fires once with
identifier: null. - On non-macOS platforms: not emitted.
Create a BrowserWindow and set its restorableIdentifier to complete the restoration. macOS will then automatically apply the saved frame and Space.
The listener must call done() when it has finished (either synchronously in a finally block, or after any asynchronous initialization). Unclaimed macOS completion handlers are dismissed only after all listeners have called done.
win.restorableIdentifier: string
Set a stable identifier to enable State Restoration for this window. macOS will automatically save and restore the window's frame and Space on next launch.
win.restorableState: any
Get or set custom data to be saved alongside the window's native state. The data is serialized as JSON and persisted by macOS.
Current supported value shapes:
- Plain objects (
{}) with string keys string,number,booleannull- Arrays containing supported values
- Nested plain objects/arrays using the same rules
Not guaranteed to round-trip correctly:
undefinedproperties (dropped on save)- Non-JSON-like values (for example
Date,Map,Set, functions)
How it works
- Window setup (
restorableIdentifier) — Settingwin.restorableIdentifiercalls into the native addon, marks the NSWindow as restorable, assigns the restoration class, and wires the window into macOS State Restoration. - Custom state encode/restore swizzle — Swizzles
encodeRestorableStateWithCoder:andrestoreStateWithCoder:on NSWindow to persist and recover customrestorableStatedata via associated objects. - Quit-time flush hook — Electron's
app.quit()does not call[NSApp terminate:], so abefore-quithook calls nativeflushState(), which invokes[NSApp terminate:]and returnsNSTerminateCancelfromapplicationShouldTerminate:so state is flushed without replacing Electron's normal quit flow. - Restoration class pending queue — The
NSWindowRestorationclass captures macOS completion handlers (and decoded saved state) until JS creates the matching BrowserWindow. restore-windowevent bridge — Duringready, pending restore requests are emitted asrestore-windowevents. The app creates windows and callsdone(), then remaining unclaimed requests are dismissed.
Relation to electron-osx-spaces
electron-osx-spaces provides manual encodeState() / restoreState() APIs for explicit control over when and how window state is saved. This package (electron-osx-restorable-state) takes a different approach — it hooks into macOS's native State Restoration cycle so everything is fully automatic. Just set restorableIdentifier and macOS handles the rest. Choose whichever fits your use case.
Platform support
- macOS: Full functionality
- Other platforms: No-op
License
MIT
