ui.addButton()
Renders an image-based button with automatic normal, clicked, and hovered states driven by a 3-frame sprite sheet. Click handling is built in via buttonAction or the standard onLeftMouseUp callback.
ui.addButton(options);INFO
Also accepts all General Element Options and General Image Options (imageAlpha, grayscale, imageTint, imageFlip, imageCrop, colorMatrix, fallbackPath).
Table of Contents
Quick Example
ui.addButton({
id: "close-btn",
x: 360, y: 8,
width: 24, height: 24,
buttonImageName: "./assets/close.png",
buttonAction: () => {
ipcRenderer.send("window-close");
}
});Sprite Sheet Format
A button image must contain exactly 3 frames representing the three button states:
| Frame index | State | When displayed |
|---|---|---|
0 | Normal | Default idle state |
1 | Clicked | Mouse button held down |
2 | Hovered | Cursor over the button |
The three frames can be arranged in one of two layouts, detected automatically by the engine:
- Horizontal — frames side by side (total width ≥ height × 3). Each frame is
imageWidth / 3wide. - Vertical — frames stacked top to bottom (total width < height × 3). Each frame is
imageHeight / 3tall.
A 72×24 image is treated as 3 horizontal frames of 24×24 each. A 24×72 image is treated as 3 vertical frames of 24×24 each.
Sizing without explicit width/height
When width and height are omitted, the element sizes itself to one frame from the sprite sheet automatically. You can still set them explicitly to scale the button.
Options
Hit Testing
By default the button uses bounding-box hit testing. When pixelHitTest: true is set, the engine performs per-pixel alpha testing against the current frame — clicks on fully transparent pixels are ignored. This allows non-rectangular buttons with irregular shapes to work correctly.
ui.addButton({
id: "round-btn",
buttonImageName: "./assets/circle-btn.png",
x: 16, y: 16,
pixelHitTest: true // transparent corners are not clickable
});Practical Examples
Toolbar button row
ui.beginUpdate();
const btnY = 8;
const btnSize = 24;
ui.addButton({ id: "btn-min", x: 316, y: btnY, width: btnSize, height: btnSize, buttonImageName: "./assets/minimize.png", buttonAction: () => ipcRenderer.send("minimize") });
ui.addButton({ id: "btn-max", x: 340, y: btnY, width: btnSize, height: btnSize, buttonImageName: "./assets/maximize.png", buttonAction: () => ipcRenderer.send("maximize") });
ui.addButton({ id: "btn-close", x: 364, y: btnY, width: btnSize, height: btnSize, buttonImageName: "./assets/close.png", buttonAction: () => ipcRenderer.send("close") });
ui.endUpdate();Toggle button using state
let muted = false;
ui.addButton({
id: "mute-btn",
x: 16, y: 16,
width: 32, height: 32,
buttonImageName: "./assets/volume-on.png",
buttonAction: () => {
muted = !muted;
ui.setElementProperties("mute-btn", {
buttonImageName: muted ? "./assets/volume-off.png" : "./assets/volume-on.png"
});
ipcRenderer.send("set-mute", { muted });
}
});Tinted button using imageTint
ui.addButton({
id: "ok-btn",
x: 16, y: 100,
width: 80, height: 30,
buttonImageName: "./assets/btn-base.png",
imageTint: "rgba(0,180,100,0.6)",
buttonAction: () => ipcRenderer.send("confirm")
});Grayscale disabled state
function setButtonEnabled(id, enabled) {
ui.setElementProperties(id, {
grayscale: !enabled,
imageAlpha: enabled ? 255 : 140
});
}
ui.addButton({
id: "submit-btn",
x: 16, y: 100,
width: 80, height: 30,
buttonImageName: "./assets/submit.png",
buttonAction: () => ipcRenderer.send("submit")
});
// Disable it
setButtonEnabled("submit-btn", false);