Usage
This page covers how window.Electron is built and consumed, the error-handling pattern every call follows, the React hooks, and how to extend the bridge with your own IPC channels. For the full grouped method list, jump to Reference: API surface at the bottom.
The window.Electron bridge
electron/preload.ts (scaffolded by dae init) builds the bridge and exposes it:
import { contextBridge, ipcRenderer } from 'electron';
import { createElectronBridge } from '@devioarts/electron/preload';
contextBridge.exposeInMainWorld('Electron', createElectronBridge());
From renderer code, every method is a typed, promise-based call over IPC:
window.Electron.minimize();
const version = await window.Electron.getAppVersion();
const platform = await window.Electron.getPlatform(); // 'darwin' | 'win32' | 'linux' | ...
Methods take positional arguments (clipboard.writeText(text)), not a single options object — this is deliberate, and plugins follow the same convention (see Plugins).
Throwing vs window.Electron.safe — two flavors of every call
Every wrapped bridge method exists in two forms side by side: the default window.Electron.<ns>.<method>(), which throws an IpcError on failure, and window.Electron.safe.<ns>.<method>(), which never throws and instead resolves an IpcResult<T> — { ok: true, data } on success, { ok: false, error: { code, message } } on failure. Both call the exact same main-process handler over the exact same IPC channel; only what happens to a failure differs. Nothing needs to be configured to use .safe — it's just a safe property already sitting on window.Electron.
// Throwing default — reach for this when a failure is exceptional
import { isIpcError } from '@devioarts/electron';
try {
await window.Electron.autoLaunch.setEnabled(true);
} catch (e) {
if (isIpcError(e) && e.code === 'UNSUPPORTED_OS') return; // expected on Linux
throw e;
}
// .safe mirror — reach for this when a failure is a normal branch to check inline
const result = await window.Electron.safe.autoLaunch.setEnabled(true);
if (!result.ok) {
if (result.error.code === 'UNSUPPORTED_OS') return; // expected on Linux
console.error(result.error.message);
}
code is one of VALIDATION, NOT_CONFIGURED, RUNTIME, UNSUPPORTED_OS, FORBIDDEN, UNKNOWN — see API reference: Error codes for what each one means.
Not every method has a .safe twin: pure event subscriptions (onDeepLink, onShortcut, onMenuAction, onPowerMonitorEvent, onScreenEvent, onAppStateChange, onElectronError) and fire-and-forget calls (updater.quitAndInstall()) can't fail in a way worth reporting, so there's nothing to unwrap either way. Some namespaces mix request/response methods with an on() subscriber — only the request/response methods get a .safe twin there. API reference: Per-namespace .safe coverage has the full breakdown, namespace by namespace.
The playground demonstrates the throwing style, centralized in playground/src/helpers/ipc.ts's unwrap() helper — logs the failure and returns undefined on a throw, otherwise returns the resolved value.
React hooks (@devioarts/electron/react)
Thin hooks over window.Electron — no new IPC, no new capability, just ergonomics: typed access and auto-cleanup event subscriptions.
useElectron(): ElectronBridge— typed access towindow.Electron. Throws if used outside Electron (no bridge present).useElectronEvent<T>(subscribe, callback)— subscribes to anywindow.Electronon*event for the component's lifetime; the(callback) => unsubscribepattern is wrapped inuseEffectso the listener is removed automatically on unmount.useNativeTheme(): NativeThemeSnapshot | null— live native theme state, subscribes tonativeTheme.onUpdated.useShortcut(): string | null— latest global-shortcut event name fired since mount.useMenuAction(): MenuActionEvent | null— latest native menu action (app/context/dock/tray) fired since mount.useScreenEvent(): ScreenEventPayload | null— latest display/screen change event since mount.
import { useElectron, useNativeTheme, useElectronEvent } from '@devioarts/electron/react';
function TitleBar() {
const electron = useElectron();
const theme = useNativeTheme();
useElectronEvent(window.Electron.onShortcut, ({ event }) => {
if (event === 'open-search') setSearchOpen(true);
});
return (
<div>
<button onClick={() => electron.minimize()}>Minimize</button>
<span>{theme?.shouldUseDarkColors ? 'dark' : 'light'}</span>
</div>
);
}
Task examples
// Native OS notification (Notification Center / Action Center / libnotify) —
// not the web Notification API, so it works even when the window isn't focused.
const id = await window.Electron.notifications.show({ title: 'Export finished' });
const unsubscribe = window.Electron.notifications.on((event) => {
if (event.id === id && event.type === 'click') showExportFolder();
});
// Clipboard images — plain text copy/paste is already covered by the
// standard navigator.clipboard Web API, no bridge needed for that.
const pngDataUrl = await window.Electron.clipboard.readImage();
// Run a pre-configured Node.js helper script (see configuration/processes.md) —
// the renderer only ever names it by alias, never by file path.
const { id: taskId } = await window.Electron.utilityProcess.start('imageResizer');
window.Electron.utilityProcess.onMessage(({ id, message }) => {
if (id === taskId) console.log('progress from worker:', message);
});
// Taskbar/Dock progress indicator — e.g. during a long download or export.
await window.Electron.setProgressBar(0.42);
await window.Electron.setProgressBar(-1); // remove it
// Native OS drag of a file out of the window (e.g. onto the desktop or another
// app) — must be called from the renderer's own `dragstart` handler, and only
// works while that drag gesture is actually in progress.
someElement.addEventListener('dragstart', () => {
void window.Electron.startFileDrag({ file: '/path/to/export.pdf', icon: '/path/to/icon.png' });
});
Extending the bridge with your own channels
Spread createElectronBridge()'s result alongside your own properties before exposing:
// electron/preload.ts
import { contextBridge, ipcRenderer } from 'electron';
import { createElectronBridge } from '@devioarts/electron/preload';
contextBridge.exposeInMainWorld('Electron', {
...createElectronBridge(),
myCustomMethod: () => ipcRenderer.invoke('myApp:doSomething'),
});
Register the matching handler in electron/main.ts with the same trusted-origin check every built-in channel uses:
import { trustedIpcHandle } from '@devioarts/electron/main';
trustedIpcHandle('myApp:doSomething', (event, arg) => {
// ...
});
Then extend the type in electron-env.d.ts (scaffolded by dae init) so window.Electron.myCustomMethod is typed:
declare module '@devioarts/electron' {
interface ElectronBridge {
myCustomMethod: () => Promise<void>;
}
}
For a reusable capability shared across projects, prefer a plugin over ad-hoc additions like this.
Reference: API surface
Every module below has its own page with the full method table (signatures, params, return types), events, and exactly which methods have a .safe twin — see API reference for the overview and the .safe coverage table. This page stays focused on task-level usage; jump to a module page once you know which one you need:
| Module | Bridge surface |
|---|---|
| System & window | Flat: quit, minimize, ..., getAppVersion, getDeviceId, setBadgeCount, setProgressBar, startFileDrag, onAppStateChange |
| Managed windows | windows.* |
| Updater | updater.* |
| Dialogs | dialogs.* |
| Secure storage | secureStorage.* |
| Protocols | protocols.* |
| Session | session.* |
| Downloads | downloads.* |
print.* |
|
| Desktop capture | desktopCapture.* |
| Auto launch | autoLaunch.* |
| Native theme | nativeTheme.* |
| External commands | externalCommands.* |
| Clipboard | clipboard.* |
| Notifications | notifications.* |
| System preferences | systemPreferences.* |
| Crash reporter | crashReporter.* |
| Utility process | utilityProcess.* |
| Power | Flat: getPowerMonitorIdleState, ..., onPowerMonitorEvent, startPowerSaveBlocker, ... |
| Screen | Flat: getAllDisplays, ..., onScreenEvent |
| Shortcuts | Flat: registerShortcut, unregisterShortcut, onShortcut |
| Menu | Flat: showContextMenu, onMenuAction |
| Deep linking | Flat: onDeepLink |
| Errors | Flat: onElectronError |
| Plugins: Built-in plugins | Filesystem.*, Preferences.*, Network.*, FileViewer.*, PrivacyScreen.* |
Next: Configuration to enable the opt-in features these methods unlock, or Plugins to add your own capability group in the same style.