Skip to content

Tray

Create trays in the main process. Images may be absolute paths or bundled views:// URLs.

import { Tray } from "electrobun/main";
const tray = new Tray({
title: "My app",
image: "views://assets/tray-icon.png",
template: true,
width: 32,
height: 32,
});
const menuState: Record<string, boolean> = {
notifications: true,
};
function updateTrayMenu() {
tray.setMenu([
{
type: "normal",
label: "Notifications",
action: "notifications",
checked: menuState.notifications,
},
{ type: "separator" },
{
type: "normal",
label: "Quit",
action: "quit",
},
]);
}
// Install the menu before listening for interaction. This is required for the
// supported Linux AppIndicator interaction path and works on every platform.
updateTrayMenu();
type TrayClickEvent = {
data: { id: number; action: string; data?: unknown };
};
tray.on("tray-clicked", (event: unknown) => {
const { action } = (event as TrayClickEvent).data;
if (action === "notifications") {
menuState.notifications = !menuState.notifications;
updateTrayMenu();
}
});
Option Type Default Purpose
title string "" Text shown by the tray backend.
image string "" views:// URL or absolute image path.
template boolean true Treat the image as a macOS template image.
width number 16 Requested image width.
height number 16 Requested image height.
import { Tray } from "electrobun/main";
const tray = new Tray({
title: "Status",
image: "views://assets/tray-icon.png",
});
tray.setTitle("Ready");
tray.setImage("views://assets/tray-ready.png");
tray.setVisible(false);
tray.setVisible(true);
const bounds = tray.getBounds();
const sameTray = Tray.getById(tray.id);
const allTrays = Tray.getAll();
void bounds;
void sameTray;
void allTrays;
tray.remove();

Use Tray.removeById(id) instead when only a stored tray ID is available.

setMenu() replaces the current menu. Tray menu normal items require type: "normal" and label; they also support action, data, submenu, enabled, checked, hidden, and tooltip.

Ayatana AppIndicator backend supports tray menus and their actions but does not expose raw primary icon activation. Linux apps should use setMenu() and handle menu actions; do not wait for an icon-only click to install the menu. A backend that exposes raw activation may emit tray-clicked with an empty action; portable apps should use explicit menu actions.