Samuel AttardandClaude 0edcdc47c0 feat: add app shims on macOS (#54932)
* feat: add app shims on macOS

An app shim is a small app, in a bundle of its own, that shows windows on
behalf of a host Electron app. The host still creates each window, loads
its page and handles its events, but the NSWindow belongs to the shim's
process, so the Dock, the app switcher, Mission Control and Stage Manager
attribute the window to the shim and not to the host.

- `app.startAppShimServer()` / `app.stopAppShimServer()` and the
  `app-shim-connected` event, which hands over an `AppShimHost`.
- A `BaseWindow` / `BrowserWindow` created with the `appShim` option has
  its native window made in that shim's process, through Chromium's
  remote_cocoa. Such a window is a new NativeWindow implementation that
  only goes through views::Widget; what remote_cocoa has no call for is
  a no-op (see docs/api/app-shim-host.md).
- The shim's executable is `Helpers/app_shim_loader` from the framework
  bundle. It links nothing from Electron: it loads the host's framework
  and calls the new `ElectronAppShimMain` export, which runs an
  `app-shim` process that connects back to the host over a Mach
  bootstrap server.
- Electron Framework gains an rpath to the folder it is in, so that it
  finds its sibling frameworks when an executable in another bundle
  loads it.

Not available in Mac App Store builds.

Co-Authored-By: Claude <noreply@anthropic.com>

* feat: app shim menus, dialogs, window chrome and review fixes

Follow-up to the first app shim commit.

Fixes from review:
- A window torn down from one of its own listeners (shim.quit() or
  win.destroy() in `show`) no longer frees the native host that is
  notifying.
- The native close button no longer leaves the shim waiting on an answer
  that was dropped with the window.
- Keys the page does not handle go back to the shim, whose menu they are
  shortcuts of, and not to the host's menu.
- stopAppShimServer() drops shims that have connected and not said hello.
- Quitting a shim asks the host without blocking and without cancelling a
  logout; quit-requested can now be answered with "no".
- Size limits and useContentSize are in content sizes; restore() and
  unmaximize() each do one thing; webContents.isFocused() works.

New:
- shim.setMenu(): a menu bar of the shim's own, built in the shim from a
  description of the Menu, with clicks sent back.
- Message boxes and open and save dialogs are sheets of the window in the
  shim's process.
- titleBarStyle, traffic light position and visibility, vibrancy, tabs and
  Quick Look, applied in the shim to the NSWindow that remote_cocoa made.
- A Chromium patch for what remote_cocoa has no call for: movable,
  closable, minimizable and fullscreenable, clearing an aspect ratio, and
  yielding activation to the hosting process by pid.
- A shim that loaded another build of Electron than the running host
  tells the host and quits: app-shim-version-mismatch.

The API is marked experimental in the docs.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: address review of app shims

- A window in an app shim can't be given a parent, at construction or
  with setParentWindow(), as the docs say.
- shim.setMenu() is now shim.setApplicationMenu().
- A message box that is showing under an id makes way for a new one with
  that id, whichever process shows it.
- Mac App Store builds no longer export the shim's entry point; they
  already had no loader.
- setProgressBar() and setHasShadow() are listed among what does nothing
  on a window in a shim.
- The spec no longer asserts inside an event listener.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: clang-tidy findings in app shim code

* docs: reword the app shim docs for clarity

* chore: update patches

Re-exported after rebasing onto Chromium 158.0.8105.0; only line offsets
changed.

Co-Authored-By: Claude <noreply@anthropic.com>

* test: use vitest matchers in the app shim spec

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-16 14:03:19 -07:00
2026-09-01 12:06:48 -04:00
2016-10-04 22:42:49 +02:00
2026-10-16 14:03:19 -07:00

Electron Logo

GitHub Actions Build Status

📝 Available Translations: 🇨🇳 🇧🇷 🇪🇸 🇯🇵 🇷🇺 🇫🇷 🇺🇸 🇩🇪. View these docs in other languages on our Crowdin project.

The Electron framework lets you write cross-platform desktop applications using JavaScript, HTML and CSS. It is based on Node.js and Chromium and is used by the Visual Studio Code and many other apps.

Follow @electronjs on Twitter for important announcements.

This project adheres to the Contributor Covenant code of conduct. By participating, you are expected to uphold this code. Please report unacceptable behavior to coc@electronjs.org.

Installation

To install prebuilt Electron binaries, use npm. The preferred method is to install Electron as a development dependency in your app:

npm install electron --save-dev

For more installation options and troubleshooting tips, see installation. For info on how to manage Electron versions in your apps, see Electron versioning.

Platform support

Each Electron release provides binaries for macOS, Windows, and Linux.

  • macOS (Ventura and up): Electron provides 64-bit Intel and Apple Silicon / ARM binaries for macOS.
  • Windows (Windows 10 and up): Electron provides x64 (amd64) and arm64 binaries for Windows.
  • Linux: Electron provides x64 (amd64) and arm64 binaries for Linux. Electron supports major Linux distributions (e.g., Ubuntu, Fedora, Debian) in versions that are still supported by both Chromium and the distro maker (without requiring a paid subscription). The prebuilt binaries are built on Ubuntu.

In general, Electron tries to align with Chromium on platform support.

Electron Fiddle

Use Electron Fiddle to build, run, and package small Electron experiments, to see code examples for all of Electron's APIs, and to try out different versions of Electron. It's designed to make the start of your journey with Electron easier.

Resources for learning Electron

Programmatic usage

Most people use Electron from the command line, but if you require electron inside your Node app (not your Electron app) it will return the file path to the binary. Use this to spawn Electron from Node scripts:

const electron = require('electron')
const proc = require('node:child_process')

// will print something similar to /Users/maf/.../Electron
console.log(electron)

// spawn Electron
const child = proc.spawn(electron)

Mirrors

See the Advanced Installation Instructions to learn how to use a custom mirror.

Documentation translations

We crowdsource translations for our documentation via Crowdin. We currently accept translations for Chinese (Simplified), French, German, Japanese, Portuguese, Russian, and Spanish.

Contributing

If you are interested in reporting/fixing issues and contributing directly to the code base, please see CONTRIBUTING.md for more information on what we're looking for and how to get started.

Community

Info on reporting bugs, getting help, finding third-party tools and sample apps, and more can be found on the Community page.

License

MIT

When using Electron logos, make sure to follow OpenJS Foundation Trademark Policy.

Languages
C++ 52.7%
TypeScript 35.9%
Objective-C++ 5.9%
JavaScript 2.6%
Python 1.6%
Other 1.2%