electron-desktop
Desktop application development with Electron for Windows, macOS, and Linux. Use when building cross-platform desktop apps, implementing native OS features, or packaging web apps for desktop.
Best use case
electron-desktop is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Desktop application development with Electron for Windows, macOS, and Linux. Use when building cross-platform desktop apps, implementing native OS features, or packaging web apps for desktop.
Teams using electron-desktop should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/electron-desktop/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How electron-desktop Compares
| Feature / Agent | electron-desktop | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Desktop application development with Electron for Windows, macOS, and Linux. Use when building cross-platform desktop apps, implementing native OS features, or packaging web apps for desktop.
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# Electron Desktop Development
Build cross-platform desktop applications using web technologies.
## Platforms Supported
| Platform | Architecture | Notes |
| -------- | -------------------------- | ------------------ |
| Windows | x64, arm64, ia32 | Windows 10+ |
| macOS | x64, arm64 (Apple Silicon) | macOS 10.15+ |
| Linux | x64, arm64, armv7l | Most distributions |
---
## Project Structure
```
my-app/
├── src/
│ ├── main/
│ │ ├── main.ts # Main process
│ │ ├── preload.ts # Preload scripts
│ │ └── ipc.ts # IPC handlers
│ ├── renderer/
│ │ ├── index.html
│ │ ├── App.tsx
│ │ └── components/
│ └── shared/
│ └── types.ts
├── resources/
│ ├── icon.icns # macOS
│ ├── icon.ico # Windows
│ └── icon.png # Linux
├── electron-builder.yml
├── package.json
└── forge.config.ts
```
---
## Main Process
### Entry Point
```typescript
// src/main/main.ts
import { app, BrowserWindow, ipcMain } from "electron";
import path from "path";
let mainWindow: BrowserWindow | null = null;
function createWindow() {
mainWindow = new BrowserWindow({
width: 1200,
height: 800,
minWidth: 800,
minHeight: 600,
webPreferences: {
preload: path.join(__dirname, "preload.js"),
contextIsolation: true,
nodeIntegration: false,
sandbox: true,
},
titleBarStyle: "hiddenInset", // macOS
frame: process.platform === "darwin", // Windows/Linux custom frame
show: false, // Show when ready
});
// Load the app
if (process.env.NODE_ENV === "development") {
mainWindow.loadURL("http://localhost:5173");
mainWindow.webContents.openDevTools();
} else {
mainWindow.loadFile(path.join(__dirname, "../renderer/index.html"));
}
// Show when ready to prevent flash
mainWindow.once("ready-to-show", () => {
mainWindow?.show();
});
mainWindow.on("closed", () => {
mainWindow = null;
});
}
app.whenReady().then(createWindow);
app.on("window-all-closed", () => {
if (process.platform !== "darwin") {
app.quit();
}
});
app.on("activate", () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
```
### Preload Script (Security Bridge)
```typescript
// src/main/preload.ts
import { contextBridge, ipcRenderer } from "electron";
// Expose safe APIs to renderer
contextBridge.exposeInMainWorld("electronAPI", {
// File operations
openFile: () => ipcRenderer.invoke("dialog:openFile"),
saveFile: (content: string) => ipcRenderer.invoke("dialog:saveFile", content),
// App info
getVersion: () => ipcRenderer.invoke("app:getVersion"),
// Window controls
minimize: () => ipcRenderer.send("window:minimize"),
maximize: () => ipcRenderer.send("window:maximize"),
close: () => ipcRenderer.send("window:close"),
// Two-way communication
onUpdateAvailable: (callback: () => void) => {
ipcRenderer.on("update:available", callback);
return () => ipcRenderer.removeListener("update:available", callback);
},
});
// Type definitions for renderer
declare global {
interface Window {
electronAPI: {
openFile: () => Promise<string | null>;
saveFile: (content: string) => Promise<boolean>;
getVersion: () => Promise<string>;
minimize: () => void;
maximize: () => void;
close: () => void;
onUpdateAvailable: (callback: () => void) => () => void;
};
}
}
```
### IPC Handlers
```typescript
// src/main/ipc.ts
import { ipcMain, dialog, BrowserWindow } from "electron";
import fs from "fs/promises";
export function setupIPC() {
// File dialogs
ipcMain.handle("dialog:openFile", async () => {
const { canceled, filePaths } = await dialog.showOpenDialog({
properties: ["openFile"],
filters: [
{ name: "Text Files", extensions: ["txt", "md"] },
{ name: "All Files", extensions: ["*"] },
],
});
if (canceled || filePaths.length === 0) return null;
return fs.readFile(filePaths[0], "utf-8");
});
ipcMain.handle("dialog:saveFile", async (_, content: string) => {
const { canceled, filePath } = await dialog.showSaveDialog({
filters: [{ name: "Text Files", extensions: ["txt"] }],
});
if (canceled || !filePath) return false;
await fs.writeFile(filePath, content);
return true;
});
// Window controls
ipcMain.on("window:minimize", (event) => {
BrowserWindow.fromWebContents(event.sender)?.minimize();
});
ipcMain.on("window:maximize", (event) => {
const win = BrowserWindow.fromWebContents(event.sender);
if (win?.isMaximized()) {
win.unmaximize();
} else {
win?.maximize();
}
});
ipcMain.on("window:close", (event) => {
BrowserWindow.fromWebContents(event.sender)?.close();
});
}
```
---
## Renderer Process (React)
### Using Exposed APIs
```tsx
// src/renderer/App.tsx
import { useState, useEffect } from "react";
function App() {
const [version, setVersion] = useState("");
const [content, setContent] = useState("");
useEffect(() => {
window.electronAPI.getVersion().then(setVersion);
const unsubscribe = window.electronAPI.onUpdateAvailable(() => {
alert("Update available!");
});
return unsubscribe;
}, []);
const handleOpen = async () => {
const fileContent = await window.electronAPI.openFile();
if (fileContent) {
setContent(fileContent);
}
};
const handleSave = async () => {
await window.electronAPI.saveFile(content);
};
return (
<div className="app">
<header className="titlebar">
<span>My App v{version}</span>
<div className="window-controls">
<button onClick={window.electronAPI.minimize}>−</button>
<button onClick={window.electronAPI.maximize}>□</button>
<button onClick={window.electronAPI.close}>×</button>
</div>
</header>
<main>
<button onClick={handleOpen}>Open File</button>
<textarea
value={content}
onChange={(e) => setContent(e.target.value)}
/>
<button onClick={handleSave}>Save File</button>
</main>
</div>
);
}
```
### Custom Title Bar CSS
```css
.titlebar {
-webkit-app-region: drag; /* Make draggable */
height: 32px;
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 16px;
background: #1e1e1e;
color: white;
}
.window-controls {
-webkit-app-region: no-drag; /* Buttons clickable */
display: flex;
gap: 8px;
}
.window-controls button {
width: 32px;
height: 32px;
border: none;
background: transparent;
color: white;
cursor: pointer;
}
.window-controls button:hover {
background: rgba(255, 255, 255, 0.1);
}
```
---
## Native Features
### System Tray
```typescript
import { Tray, Menu, nativeImage } from "electron";
let tray: Tray | null = null;
function createTray() {
const icon = nativeImage.createFromPath("resources/tray-icon.png");
tray = new Tray(icon.resize({ width: 16, height: 16 }));
const contextMenu = Menu.buildFromTemplate([
{ label: "Show App", click: () => mainWindow?.show() },
{ type: "separator" },
{ label: "Quit", click: () => app.quit() },
]);
tray.setToolTip("My App");
tray.setContextMenu(contextMenu);
tray.on("click", () => {
mainWindow?.show();
});
}
```
### Native Menus
```typescript
import { Menu } from "electron";
const template: Electron.MenuItemConstructorOptions[] = [
{
label: "File",
submenu: [
{
label: "Open",
accelerator: "CmdOrCtrl+O",
click: () => {
/* handle */
},
},
{
label: "Save",
accelerator: "CmdOrCtrl+S",
click: () => {
/* handle */
},
},
{ type: "separator" },
{ role: "quit" },
],
},
{
label: "Edit",
submenu: [
{ role: "undo" },
{ role: "redo" },
{ type: "separator" },
{ role: "cut" },
{ role: "copy" },
{ role: "paste" },
],
},
];
Menu.setApplicationMenu(Menu.buildFromTemplate(template));
```
### Notifications
```typescript
import { Notification } from "electron";
new Notification({
title: "Update Available",
body: "A new version is ready to install.",
icon: "resources/icon.png",
}).show();
```
### Auto Updates
```typescript
import { autoUpdater } from "electron-updater";
autoUpdater.checkForUpdatesAndNotify();
autoUpdater.on("update-available", () => {
mainWindow?.webContents.send("update:available");
});
autoUpdater.on("update-downloaded", () => {
autoUpdater.quitAndInstall();
});
```
---
## Building & Distribution
### electron-builder Configuration
```yaml
# electron-builder.yml
appId: com.mycompany.myapp
productName: My App
copyright: Copyright © 2025
directories:
output: dist
buildResources: resources
files:
- dist/**/*
- package.json
mac:
category: public.app-category.developer-tools
target:
- target: dmg
arch: [x64, arm64]
- target: zip
arch: [x64, arm64]
hardenedRuntime: true
gatekeeperAssess: false
entitlements: build/entitlements.mac.plist
notarize: true
win:
target:
- target: nsis
arch: [x64]
sign: true
linux:
target:
- target: AppImage
- target: deb
- target: rpm
category: Development
publish:
provider: github
releaseType: release
```
### Build Commands
```bash
# Development
npm run dev
# Build for current platform
npm run build
# Build for all platforms
npm run build:all
# Build for specific platform
npm run build:mac
npm run build:win
npm run build:linux
```
---
## Security Best Practices
### DO:
- Always use `contextIsolation: true`
- Use preload scripts for IPC
- Validate all IPC inputs
- Enable `sandbox: true`
- Sign and notarize for distribution
### DON'T:
- Enable `nodeIntegration`
- Use `remote` module
- Load untrusted content
- Expose full Node.js APIs
- Skip code signing
---
## Alternatives to Consider
| Framework | Best For |
| -------------- | ------------------------------ |
| **Tauri** | Smaller bundle, Rust backend |
| **Neutralino** | Lightweight, system webview |
| **Electron** | Full Node.js, mature ecosystem |Related Skills
tauri-desktop
Tauri 2.0 project setup, Rust backend + web frontend, plugin system, IPC commands, security model, auto-update, and mobile support. Use when building lightweight cross-platform desktop or mobile apps with Tauri.
example-skill
Example skill - replace with your skill's description and activation keywords
websockets-realtime
Real-time communication with WebSockets, Server-Sent Events, and related technologies. Use when building chat, live updates, collaborative features, or any real-time functionality.
video-production
Professional video production from planning to delivery. Use when creating video content, editing workflows, motion graphics, or optimizing video for different platforms.
ui-research
Research-first UI/UX design workflow. Use BEFORE any frontend visual work to research modern patterns, gather inspiration from real products, and avoid generic AI-generated looks. Mandatory prerequisite for quality UI work.
ui-animation
Motion design and animation for user interfaces. Use when creating micro-interactions, page transitions, loading states, or any UI animation across web and mobile platforms.
travel-planner
Travel destination research and daily itinerary creation with logistics planning, budget tracking, and experience optimization. Use when planning trips, creating travel itineraries, comparing destinations, or organizing travel logistics.
test-specialist
This skill should be used when writing test cases, fixing bugs, analyzing code for potential issues, or improving test coverage for JavaScript/TypeScript applications. Use this for unit tests, integration tests, end-to-end tests, debugging runtime errors, logic bugs, performance issues, security vulnerabilities, and systematic code analysis.
tech-debt-analyzer
This skill should be used when analyzing technical debt in a codebase, documenting code quality issues, creating technical debt registers, or assessing code maintainability. Use this for identifying code smells, architectural issues, dependency problems, missing documentation, security vulnerabilities, and creating comprehensive technical debt documentation.
tdd-workflow
Test-Driven Development workflow enforcement with RED-GREEN-REFACTOR cycle. Use when implementing features test-first or improving test coverage.
svelte-development
Svelte 5 development with runes ($state, $derived, $effect), SvelteKit full-stack framework, and modern reactive patterns. Use when building Svelte applications, implementing fine-grained reactivity, or working with SvelteKit routing and server functions.
sustainability-esg
Sustainability and ESG expertise for ESG strategy, carbon footprint management, sustainable supply chains, circular economy, renewable energy, climate risk, and ESG reporting (GRI, SASB, TCFD). Use when building sustainability programs, measuring carbon impact, or creating ESG reports.