Skip to main content

Menu & Shortcut API

Native menus and global keyboard shortcuts for Krema applications.

Application Menu

Sets the application's main menu bar.

await window.krema.invoke('menu:setApplicationMenu', {
menu: [
{
label: 'File',
submenu: [
{ id: 'new', label: 'New', accelerator: 'CmdOrCtrl+N' },
{ id: 'open', label: 'Open...', accelerator: 'CmdOrCtrl+O' },
{ type: 'separator' },
{ id: 'save', label: 'Save', accelerator: 'CmdOrCtrl+S' },
{ type: 'separator' },
{ role: 'quit' }
]
},
{
label: 'Edit',
submenu: [
{ role: 'undo' },
{ role: 'redo' },
{ type: 'separator' },
{ role: 'cut' },
{ role: 'copy' },
{ role: 'paste' },
{ role: 'selectAll' }
]
},
{
label: 'View',
submenu: [
{ id: 'theme-light', label: 'Light Theme', type: 'radio', checked: true },
{ id: 'theme-dark', label: 'Dark Theme', type: 'radio' },
{ type: 'separator' },
{ role: 'toggleFullScreen' }
]
}
]
});
PropertyTypeDescription
idstringUnique identifier for click events
labelstringDisplay text
typestring'normal', 'separator', 'checkbox', 'radio', 'submenu'
acceleratorstringKeyboard shortcut
enabledbooleanWhether item is clickable (default: true)
checkedbooleanFor checkbox/radio items
submenuarrayNested menu items
rolestringPredefined system role

Accelerator Format

CmdOrCtrl+S        // Cmd on macOS, Ctrl elsewhere
Cmd+Shift+Z // macOS only
Ctrl+Alt+Delete // Windows/Linux
F11 // Function key

Modifiers: Cmd, Ctrl, CmdOrCtrl, Alt, Option, Shift, Super

Predefined Roles

RoleAction
aboutAbout dialog
quitQuit application
undoUndo
redoRedo
cutCut selection
copyCopy selection
pastePaste
selectAllSelect all
minimizeMinimize window
closeClose window
toggleFullScreenToggle fullscreen
frontBring all windows to front
hideHide app (macOS)
hideOthersHide other apps (macOS)
unhideShow all (macOS)

Context Menus

Shows a context menu at a position.

await window.krema.invoke('menu:showContextMenu', {
items: [
{ id: 'copy', label: 'Copy', accelerator: 'CmdOrCtrl+C' },
{ id: 'paste', label: 'Paste', accelerator: 'CmdOrCtrl+V' },
{ type: 'separator' },
{ id: 'delete', label: 'Delete', enabled: hasSelection }
],
x: event.clientX,
y: event.clientY
});

Dock Menu (macOS)

Sets the dock icon right-click menu.

await window.krema.invoke('menu:setDockMenu', {
menu: [
{ id: 'new-window', label: 'New Window' },
{ id: 'new-tab', label: 'New Tab' },
{ type: 'separator' },
{ id: 'recent-1', label: 'Recent Document 1' },
{ id: 'recent-2', label: 'Recent Document 2' }
]
});

Listen for menu item clicks.

window.krema.on('menu:click', (data) => {
switch (data.id) {
case 'new':
createNewDocument();
break;
case 'open':
openFile();
break;
case 'theme-light':
setTheme('light');
break;
case 'theme-dark':
setTheme('dark');
break;
}
});

Updates a menu item's state.

// Toggle checkbox
await window.krema.invoke('menu:updateItem', {
id: 'auto-save',
checked: true
});

// Disable item
await window.krema.invoke('menu:updateItem', {
id: 'save',
enabled: false
});

Global Shortcuts

Global shortcuts work even when the app is not focused.

shortcut:register

Registers a global shortcut.

const success = await window.krema.invoke('shortcut:register', {
accelerator: 'CmdOrCtrl+Shift+Space'
});

shortcut:unregister

Removes a registered shortcut.

await window.krema.invoke('shortcut:unregister', {
accelerator: 'CmdOrCtrl+Shift+Space'
});

shortcut:unregisterAll

Removes all registered shortcuts.

await window.krema.invoke('shortcut:unregisterAll');

shortcut:isRegistered

Checks if a shortcut is registered.

const registered = await window.krema.invoke('shortcut:isRegistered', {
accelerator: 'CmdOrCtrl+Shift+Space'
});

shortcut:getAll

Lists all registered shortcuts.

const shortcuts = await window.krema.invoke('shortcut:getAll');
// ['CmdOrCtrl+Shift+Space', 'CmdOrCtrl+Shift+V']

shortcut:triggered Event

Listen for shortcut activations.

window.krema.on('shortcut:triggered', (data) => {
if (data.accelerator === 'CmdOrCtrl+Shift+Space') {
toggleQuickSearch();
}
});

Examples

Complete Application Menu

async function setupMenu() {
const isMac = (await window.krema.invoke('os:platform')) === 'macos';

const appMenu = isMac ? [{
label: 'App Name',
submenu: [
{ role: 'about' },
{ type: 'separator' },
{ role: 'hide' },
{ role: 'hideOthers' },
{ role: 'unhide' },
{ type: 'separator' },
{ role: 'quit' }
]
}] : [];

await window.krema.invoke('menu:setApplicationMenu', {
menu: [
...appMenu,
{
label: 'File',
submenu: [
{ id: 'new', label: 'New', accelerator: 'CmdOrCtrl+N' },
{ id: 'open', label: 'Open...', accelerator: 'CmdOrCtrl+O' },
{ type: 'separator' },
isMac ? { role: 'close' } : { role: 'quit' }
]
},
{
label: 'Edit',
submenu: [
{ role: 'undo' },
{ role: 'redo' },
{ type: 'separator' },
{ role: 'cut' },
{ role: 'copy' },
{ role: 'paste' },
...(isMac ? [
{ role: 'selectAll' },
{ type: 'separator' },
{
label: 'Speech',
submenu: [
{ role: 'startSpeaking' },
{ role: 'stopSpeaking' }
]
}
] : [
{ role: 'selectAll' }
])
]
}
]
});
}

Context Menu on Right-Click

document.addEventListener('contextmenu', async (e) => {
e.preventDefault();

const selection = window.getSelection().toString();

await window.krema.invoke('menu:showContextMenu', {
items: [
{ id: 'cut', label: 'Cut', accelerator: 'CmdOrCtrl+X', enabled: !!selection },
{ id: 'copy', label: 'Copy', accelerator: 'CmdOrCtrl+C', enabled: !!selection },
{ id: 'paste', label: 'Paste', accelerator: 'CmdOrCtrl+V' },
{ type: 'separator' },
{ id: 'inspect', label: 'Inspect Element' }
],
x: e.clientX,
y: e.clientY
});
});

window.krema.on('menu:click', async ({ id }) => {
switch (id) {
case 'cut':
document.execCommand('cut');
break;
case 'copy':
document.execCommand('copy');
break;
case 'paste':
const text = await window.krema.invoke('clipboard:readText');
document.execCommand('insertText', false, text);
break;
}
});
async function setupQuickSearch() {
// Register global shortcut
await window.krema.invoke('shortcut:register', {
accelerator: 'CmdOrCtrl+Shift+Space'
});

// Listen for activation
window.krema.on('shortcut:triggered', async (data) => {
if (data.accelerator === 'CmdOrCtrl+Shift+Space') {
// Show/focus the app
await window.krema.invoke('window:show');
await window.krema.invoke('window:focus');

// Focus search input
document.getElementById('search-input').focus();
}
});
}

// Clean up on exit
window.addEventListener('beforeunload', async () => {
await window.krema.invoke('shortcut:unregisterAll');
});

Platform Notes

  • macOS: Application menu appears in the system menu bar. First menu should be the app name.
  • Windows/Linux: Menu bar appears in the window. No app-name menu needed.
  • Global shortcuts: May conflict with system shortcuts. Test on all platforms.
  • Dock menu: macOS only. On Windows, use system tray menu instead.