How Draw.io Desktop Implements a Custom Context Menu with Paste and Match Style

Draw.io Desktop leverages the electron-context-menu library in src/main/electron.js to inject a "Paste and Match Style" option that appears only when plain text exists on the clipboard, executing browserWindow.webContents.pasteAndMatchStyle() to strip formatting during paste operations.

The jgraph/drawio-desktop application provides a native-like editing experience by customizing the right-click menu in its Electron-based interface. The implementation of the custom context menu, specifically the "Paste and Match Style" functionality, demonstrates how to extend default Electron menus with conditional logic and clipboard-aware visibility controls.

Electron Context Menu Architecture

The application builds its menu system on top of the third-party electron-context-menu package, which automatically attaches to all renderer windows and provides hooks for custom extensions.

Library Integration in the Main Process

In src/main/electron.js (lines 16-17), the module imports the library alongside standard Electron APIs:

import { clipboard, BrowserWindow } from 'electron';
import contextMenu from 'electron-context-menu';

Configuring the Append Callback

The configuration occurs at lines 53-71 of src/main/electron.js, where the contextMenu() function receives an append callback. This callback injects the custom "Paste and Match Style" entry into the default menu array:

contextMenu({
    showCopyImage: true,
    showSaveImage: true,
    showSaveImageAs: true,
    showLookUpSelection: false,
    showSearchWithGoogle: false,
    showCopyLink: false,
    showSelectAll: true,
    append: (defaultActions, params, browserWindow) => [
        {
            label: 'Paste and Match Style',
            visible: clipboard.availableFormats().includes('text/plain'),
            click: () => {
                browserWindow.webContents.pasteAndMatchStyle();
            }
        }
    ]
});

Conditional Visibility and Execution Logic

The visible property dynamically controls menu item availability by checking clipboard.availableFormats() for the 'text/plain' type. When the user clicks the option, the click handler invokes browserWindow.webContents.pasteAndMatchStyle(), an Electron API that inserts clipboard content without source formatting—effectively matching the destination style.

Dependency and Project Structure

The electron-context-menu dependency is declared in package.json under the standard dependencies section. No native modules are required, as the implementation relies purely on Electron's built-in clipboard and webContents APIs.

While src/main/electron-preload.js establishes the secure IPC bridge for renderer communication, the context menu logic remains entirely within the main process, with menu actions directly manipulating web contents.

Standalone Implementation Example

To replicate this pattern in a minimal Electron application:

// main.js
import { app, BrowserWindow, clipboard } from 'electron';
import contextMenu from 'electron-context-menu';

function createWindow () {
  const win = new BrowserWindow({ 
    webPreferences: { nodeIntegration: false } 
  });
  win.loadURL('https://example.com');
}

app.whenReady().then(() => {
  contextMenu({
    showSelectAll: true,
    append: (defaultActions, params, browserWindow) => [{
      label: 'Paste and Match Style',
      visible: clipboard.availableFormats().includes('text/plain'),
      click: () => browserWindow.webContents.pasteAndMatchStyle()
    }]
  });

  createWindow();
});

Extending with Additional Custom Actions

Developers can augment the menu array returned by the append function with multiple custom entries. Each object supports label, visible, enabled, and click properties, allowing complex conditional logic based on params.selectionText or other browser window attributes.

Summary

  • Draw.io Desktop uses electron-context-menu in src/main/electron.js to customize the right-click experience
  • The "Paste and Match Style" option appears only when clipboard.availableFormats() contains 'text/plain'
  • Execution calls browserWindow.webContents.pasteAndMatchStyle() to paste unformatted text
  • Configuration spans lines 53-71, with library imports at lines 16-17
  • The implementation requires no native code, relying solely on standard Electron APIs

Frequently Asked Questions

How does Draw.io detect when to show the "Paste and Match Style" option?

The menu item's visible property checks clipboard.availableFormats().includes('text/plain') to determine if plain text exists on the system clipboard. If no plain text is available, the option remains hidden from the context menu.

What is the difference between standard paste and pasteAndMatchStyle?

Standard paste operations preserve source formatting from the clipboard, while pasteAndMatchStyle() strips all formatting and inserts the content using the destination's current text styles. This matches the behavior of "Paste and Match Style" commands in native macOS and Windows applications.

Can I add other custom items to the Draw.io context menu?

Yes. The append callback in src/main/electron.js returns an array of menu item objects. Developers can add additional entries with custom labels, visibility conditions based on params.selectionText, and click handlers that invoke browserWindow.webContents methods or IPC calls to the renderer process.

Where is the electron-context-menu dependency declared?

The dependency is listed in package.json under the dependencies section, ensuring it installs automatically with the project. The library is then imported at line 16 of src/main/electron.js and instantiated immediately after command-line option handling.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →