Skip to content

/desktop-multiwindow-electron

Multi-window management, WebContentsView, BaseWindow, window lifecycle, inter-window communication, state persistence

shell
$ npx -y skills add agents-inc/skills --skill desktop-multiwindow-electron --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.
  • You can call itInvoke it directly when you want it.
  • Slash command/desktop-multiwindow-electron
How auto-invocation works

Context preview

The summary Claude sees to decide when to auto-load this skill.

Multi-window management, WebContentsView, BaseWindow, window lifecycle, inter-window communication, state persistence

SKILL.md

desktop-multiwindow-electron.SKILL.md
name: desktop-multiwindow-electron
description: Multi-window management, WebContentsView, BaseWindow, window lifecycle, inter-window communication, state persistence

Electron Multi-Window Patterns

> **Quick Guide:** Use `BrowserWindow` for single-view windows. Use `BaseWindow` + `WebContentsView` for multi-view layouts (tabs, split panes, panels). `BrowserView` is deprecated since Electron 30 -- migrate to `WebContentsView`. Track windows with a `Map<string, BrowserWindow>` registry. Communicate between windows via the main process or `MessagePort` for direct renderer-to-renderer channels. Persist window bounds manually or use the upcoming `windowStatePersistence` API. Always close `webContents` explicitly when using `BaseWindow` -- unlike `BrowserWindow`, it does not auto-cleanup.

---

<critical_requirements>

CRITICAL: Before Using This Skill

> **All code must follow project conventions in CLAUDE.md** (kebab-case, named exports, import ordering, `import type`, named constants)

**(You MUST close `webContents` explicitly when destroying a `BaseWindow` -- it does not auto-cleanup like `BrowserWindow`, causing memory leaks)**

**(You MUST use `WebContentsView` instead of `BrowserView` -- `BrowserView` is deprecated since Electron 30)**

**(You MUST route all inter-window communication through the main process or `MessagePort` -- never access another window's renderer directly)**

**(You MUST validate that saved window bounds are on a visible display before restoring -- monitors may disconnect between sessions)**

</critical_requirements>

---

**Auto-detection:** multi-window, BaseWindow, WebContentsView, BrowserView migration, contentView, addChildView, removeChildView, parent window, child window, modal window, window registry, MessagePort, MessageChannelMain, window state persistence, screen API, workArea, getAllDisplays, split view, tabs, panels, window lifecycle, ready-to-show, window-all-closed

**When to use:**

  • Creating multi-view layouts (tabs, split panes, embedded panels) with BaseWindow + WebContentsView
  • Managing multiple BrowserWindow instances with a window registry
  • Migrating from deprecated BrowserView to WebContentsView
  • Setting up parent/child or modal windows
  • Communicating between windows (via main process relay or MessagePort)
  • Persisting and restoring window position, size, and display state
  • Placing windows on specific monitors using the screen API

**When NOT to use:**

  • Single-window apps with one view (`BrowserWindow` is sufficient on its own)
  • Choosing a UI framework for the renderer
  • IPC patterns between main and a single renderer (basic IPC is outside multi-window scope)
  • Styling or layout within a single renderer

**Key patterns covered:**

  • BaseWindow + WebContentsView for multi-view layouts
  • BrowserView to WebContentsView migration
  • Window lifecycle events (ready-to-show, close, closed)
  • Parent/child and modal windows
  • Window registry with Map-based tracking
  • Inter-window communication via main process and MessagePort
  • Window state persistence (bounds, maximized, fullscreen)
  • Multi-monitor placement with screen API

---

<philosophy>

Philosophy

Electron's window model has two tiers. **BrowserWindow** is the simple path: one window, one web view, automatic lifecycle management. **BaseWindow + WebContentsView** is the flexible path: one window shell containing multiple independently managed web views, each with its own renderer process and preload script.

The key architectural decision: **use BrowserWindow for single-view windows, BaseWindow for multi-view layouts.** BaseWindow trades convenience for control -- you manage view lifecycle, bounds, and cleanup explicitly.

**When to use BaseWindow + WebContentsView:**

  • Tab bars, split editors, preview panels, embedded browser views
  • Any layout where multiple independent web pages share one OS window
  • Applications migrating from deprecated BrowserView

**When NOT to use BaseWindow:**

  • Single-view windows (BrowserWindow is simpler and handles cleanup automatically)
  • Windows that only need a toolbar or status bar (a single BrowserWindow with HTML layout is sufficient)

</philosophy>

---

<patterns>

Core Patterns

Pattern 1: BaseWindow with WebContentsView

BaseWindow is the window shell; WebContentsView instances are the content. Each view has its own renderer process and preload script.

const { BaseWindow, WebContentsView } = require("electron");

const win = new BaseWindow({ width: 1200, height: 800 });

const sidebar = new WebContentsView({
  webPreferences: { preload: path.join(__dirname, "preload.js") },
});
const main = new WebContentsView({
  webPreferences: { preload: path.join(__dirname, "preload.js") },
});

win.contentView.addChildView(sidebar);
win.contentView.addChildView(main);

const SIDEBAR_WIDTH = 250;
sidebar.setBounds({ x: 0, y: 0, width: SIDEBAR_WIDTH, height: 800 });
main.setBounds({ x: SIDEBAR_WIDTH, y: 0, width: 950, height: 800 });

sidebar.webContents.loadFile("sidebar.html");
main.webContents.loadFile("main.html");

**Key point:** Each WebContentsView needs its own `webPreferences` and preload script. BaseWindow has no `webContents` of its own. See [examples/core.md](examples/core.md) for complete split-view and tab examples with resize handling.

---

Pattern 2: BrowserView to WebContentsView Migration

BrowserView is deprecated since Electron 30. Migration is straightforward -- constructors have the same shape.

| Deprecated (BrowserView) | Replacement (WebContentsView) | | ------------------------------------------- | ---------------------------------------------------------- | | `new BrowserView(opts)` | `new WebContentsView(opts)` | | `win.addBrowserView(view)` | `win.contentView.addChildView(view)` | | `win.removeBrowserView(view)` | `win.contentView.re

Read more
Read it on GitHub ↗

Showing the first part of this file.

Ships withagents-inc-skills

The official skills marketplace for Agents Inc. 150+ skills covering everything from React and Prisma to Redis, ElevenLabs, and infrastructure tooling. Pick the skills that match your stack and install them via Claude Code. Need more control?

Get the whole plugin, auto-invoked