Build cross-platform desktop apps with JavaScript, HTML, and CSS
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Native menu system, including application menus, context menus, and platform-specific UI components like Touch Bar.
Application and context menu management.
/**
* Create native application menus and context menus
*/
class Menu {
/** Sets the application menu in macOS. On Windows and Linux, the menu will be set as each window's top menu */
static setApplicationMenu(menu: Menu | null): void;
/** Returns the application menu, if set, or null, if not set */
static getApplicationMenu(): Menu | null;
/** Sends the action to the first responder of application. This is used for emulating default macOS menu behaviors */
static sendActionToFirstResponder(action: string): void;
/** Generally, the template is an array of options for constructing a MenuItem */
static buildFromTemplate(template: Array<MenuItemConstructorOptions | MenuItem>): Menu;
/** Pops up this menu as a context menu in the BrowserWindow */
popup(options?: PopupOptions): void;
/** Closes the context menu in the browserWindow */
closePopup(browserWindow?: BrowserWindow): void;
/** Appends the menuItem to the menu */
append(menuItem: MenuItem): void;
/** Returns the item with the specified id */
getMenuItemById(id: string): MenuItem | null;
/** Inserts the menuItem to the pos position of the menu */
insert(pos: number, menuItem: MenuItem): void;
/** A MenuItem[] array containing the menu's items */
readonly items: MenuItem[];
}Usage Examples:
const { Menu, MenuItem, BrowserWindow, app } = require('electron');
// Create application menu
function createApplicationMenu() {
const template = [
{
label: 'File',
submenu: [
{
label: 'New',
accelerator: 'CmdOrCtrl+N',
click: () => {
createNewDocument();
}
},
{
label: 'Open',
accelerator: 'CmdOrCtrl+O',
click: async () => {
await openFile();
}
},
{
label: 'Save',
accelerator: 'CmdOrCtrl+S',
click: () => {
saveFile();
}
},
{ type: 'separator' },
{
label: 'Exit',
accelerator: process.platform === 'darwin' ? 'Cmd+Q' : 'Ctrl+Q',
click: () => {
app.quit();
}
}
]
},
{
label: 'Edit',
submenu: [
{ role: 'undo' },
{ role: 'redo' },
{ type: 'separator' },
{ role: 'cut' },
{ role: 'copy' },
{ role: 'paste' },
{ role: 'selectall' }
]
},
{
label: 'View',
submenu: [
{ role: 'reload' },
{ role: 'forcereload' },
{ role: 'toggledevtools' },
{ type: 'separator' },
{ role: 'resetzoom' },
{ role: 'zoomin' },
{ role: 'zoomout' },
{ type: 'separator' },
{ role: 'togglefullscreen' }
]
},
{
label: 'Window',
submenu: [
{ role: 'minimize' },
{ role: 'close' }
]
}
];
// macOS specific menu adjustments
if (process.platform === 'darwin') {
template.unshift({
label: app.getName(),
submenu: [
{ role: 'about' },
{ type: 'separator' },
{ role: 'services' },
{ type: 'separator' },
{ role: 'hide' },
{ role: 'hideothers' },
{ role: 'unhide' },
{ type: 'separator' },
{ role: 'quit' }
]
});
// Window menu
template[4].submenu = [
{ role: 'close' },
{ role: 'minimize' },
{ role: 'zoom' },
{ type: 'separator' },
{ role: 'front' }
];
}
const menu = Menu.buildFromTemplate(template);
Menu.setApplicationMenu(menu);
}
// Create context menu
function createContextMenu() {
const contextMenu = Menu.buildFromTemplate([
{
label: 'Copy',
accelerator: 'CmdOrCtrl+C',
click: () => {
clipboard.writeText(getSelectedText());
}
},
{
label: 'Paste',
accelerator: 'CmdOrCtrl+V',
click: () => {
insertText(clipboard.readText());
}
},
{ type: 'separator' },
{
label: 'Select All',
accelerator: 'CmdOrCtrl+A',
click: () => {
selectAll();
}
},
{ type: 'separator' },
{
label: 'Inspect Element',
click: (menuItem, browserWindow, event) => {
browserWindow.webContents.inspectElement(event.x, event.y);
}
}
]);
return contextMenu;
}
// Show context menu on right click
function setupContextMenu(window) {
window.webContents.on('context-menu', (event, params) => {
const contextMenu = createContextMenu();
contextMenu.popup({
window: window,
x: params.x,
y: params.y
});
});
}Individual menu items with various types and behaviors.
/**
* Add items to native application menus and context menus
*/
class MenuItem {
/** Create a new menu item */
constructor(options: MenuItemConstructorOptions);
/** A string indicating the visibility of the item */
enabled: boolean;
/** A boolean indicating whether the item is visible */
visible: boolean;
/** A boolean indicating whether the item is checked */
checked: boolean;
/** A string representing the menu items label */
label: string;
/** A function that is fired when the MenuItem receives a click event */
click: (menuItem: MenuItem, browserWindow: BrowserWindow | undefined, event: KeyboardEvent) => void;
/** A Menu that the item is a part of */
menu: Menu;
/** A Menu (optional) containing the menu item's submenu, if present */
submenu: Menu | undefined;
/** A string representing the menu item's type */
type: 'normal' | 'separator' | 'submenu' | 'checkbox' | 'radio';
/** A string (optional) representing the menu item's role */
role: MenuItemRole | undefined;
/** A string (optional) representing the menu item's accelerator */
accelerator: string | undefined;
/** A NativeImage (optional) that is displayed on the left of the menu item */
icon: NativeImage | undefined;
/** A string representing the item's sublabel */
sublabel: string;
/** A string representing the item's tooltip */
toolTip: string;
/** A string representing the item's id */
id: string;
}macOS Touch Bar support for MacBook Pro models.
/**
* Create TouchBar layouts for native macOS applications
*/
class TouchBar {
/** Create a new TouchBar with the specified items */
constructor(options: TouchBarConstructorOptions);
/** A string representing the description of the TouchBar */
static TouchBarButton: typeof TouchBarButton;
static TouchBarColorPicker: typeof TouchBarColorPicker;
static TouchBarGroup: typeof TouchBarGroup;
static TouchBarLabel: typeof TouchBarLabel;
static TouchBarPopover: typeof TouchBarPopover;
static TouchBarScrubber: typeof TouchBarScrubber;
static TouchBarSegmentedControl: typeof TouchBarSegmentedControl;
static TouchBarSlider: typeof TouchBarSlider;
static TouchBarSpacer: typeof TouchBarSpacer;
/** The escape item to replace the "esc" button on the touch bar */
escapeItem: TouchBarButton | TouchBarColorPicker | TouchBarGroup | TouchBarLabel | TouchBarPopover | TouchBarScrubber | TouchBarSegmentedControl | TouchBarSlider | TouchBarSpacer | null;
}
class TouchBarButton {
constructor(options: TouchBarButtonConstructorOptions);
label: string;
accessibilityLabel: string;
backgroundColor: string;
icon: NativeImage | undefined;
iconPosition: 'left' | 'right' | 'overlay';
enabled: boolean;
}
class TouchBarLabel {
constructor(options: TouchBarLabelConstructorOptions);
label: string;
accessibilityLabel: string;
textColor: string;
}
class TouchBarSpacer {
constructor(options: TouchBarSpacerConstructorOptions);
size: 'small' | 'large' | 'flexible';
}Usage Examples:
// macOS TouchBar setup
const { TouchBar } = require('electron');
const { TouchBarLabel, TouchBarButton, TouchBarSpacer } = TouchBar;
function setupTouchBar(window) {
if (process.platform !== 'darwin') return;
const touchBar = new TouchBar({
items: [
new TouchBarButton({
label: '🔍 Search',
backgroundColor: '#7851A9',
click: () => {
openSearchDialog();
}
}),
new TouchBarSpacer({ size: 'small' }),
new TouchBarButton({
label: '📁 Open',
click: () => {
openFile();
}
}),
new TouchBarButton({
label: '💾 Save',
click: () => {
saveFile();
}
}),
new TouchBarSpacer({ size: 'flexible' }),
new TouchBarLabel({
label: 'Ready',
textColor: '#00FF00'
})
]
});
window.setTouchBar(touchBar);
}
// Dynamic TouchBar updates
function updateTouchBarStatus(window, status) {
const statusLabel = new TouchBarLabel({
label: status,
textColor: status === 'Error' ? '#FF0000' : '#00FF00'
});
const touchBar = new TouchBar({
items: [
new TouchBarButton({
label: '🔄 Refresh',
click: () => {
window.webContents.reload();
}
}),
new TouchBarSpacer({ size: 'flexible' }),
statusLabel
]
});
window.setTouchBar(touchBar);
}interface MenuItemConstructorOptions {
click?: (menuItem: MenuItem, browserWindow: BrowserWindow | undefined, event: KeyboardEvent) => void;
role?: MenuItemRole;
type?: 'normal' | 'separator' | 'submenu' | 'checkbox' | 'radio';
label?: string;
sublabel?: string;
toolTip?: string;
accelerator?: Accelerator;
icon?: NativeImage | string;
enabled?: boolean;
acceleratorWorksWhenHidden?: boolean;
visible?: boolean;
checked?: boolean;
registerAccelerator?: boolean;
sharingItem?: SharingItem;
submenu?: Array<MenuItemConstructorOptions | MenuItem> | Menu;
id?: string;
before?: string[];
after?: string[];
beforeGroupContaining?: string[];
afterGroupContaining?: string[];
}
type MenuItemRole =
| 'undo'
| 'redo'
| 'cut'
| 'copy'
| 'paste'
| 'pasteandmatchstyle'
| 'delete'
| 'selectall'
| 'reload'
| 'forcereload'
| 'toggledevtools'
| 'resetzoom'
| 'zoomin'
| 'zoomout'
| 'toggleSpellChecker'
| 'togglefullscreen'
| 'window'
| 'minimize'
| 'close'
| 'help'
| 'about'
| 'services'
| 'hide'
| 'hideothers'
| 'unhide'
| 'quit'
| 'startSpeaking'
| 'stopSpeaking'
| 'zoom'
| 'front'
| 'appMenu'
| 'fileMenu'
| 'editMenu'
| 'viewMenu'
| 'recentDocuments'
| 'toggleTabBar'
| 'selectNextTab'
| 'selectPreviousTab'
| 'mergeAllWindows'
| 'clearRecentDocuments'
| 'moveTabToNewWindow'
| 'windowMenu';
interface PopupOptions {
window?: BrowserWindow;
x?: number;
y?: number;
positioningItem?: number;
callback?: () => void;
}
interface SharingItem {
texts?: string[];
filePaths?: string[];
urls?: string[];
}
interface TouchBarConstructorOptions {
items?: Array<TouchBarButton | TouchBarColorPicker | TouchBarGroup | TouchBarLabel | TouchBarPopover | TouchBarScrubber | TouchBarSegmentedControl | TouchBarSlider | TouchBarSpacer>;
escapeItem?: TouchBarButton | TouchBarColorPicker | TouchBarGroup | TouchBarLabel | TouchBarPopover | TouchBarScrubber | TouchBarSegmentedControl | TouchBarSlider | TouchBarSpacer;
}
interface TouchBarButtonConstructorOptions {
label?: string;
accessibilityLabel?: string;
backgroundColor?: string;
icon?: NativeImage | string;
iconPosition?: 'left' | 'right' | 'overlay';
enabled?: boolean;
click?: () => void;
}
interface TouchBarLabelConstructorOptions {
label?: string;
accessibilityLabel?: string;
textColor?: string;
}
interface TouchBarSpacerConstructorOptions {
size?: 'small' | 'large' | 'flexible';
}
type Accelerator = string;Install with Tessl CLI
npx tessl i tessl/npm-electron