app.statusbar - Menu Bar Icon API
Creates and manages standalone macOS menu bar (status bar) icons and menus.
Pick the right one first. There are two ways to put plugin functionality in the menu bar, and they are entirely different mechanisms:
showInStatusBar: trueinplugin.jsonapp.statusbar.create()Appears in iRightMenu’s own status bar menu Your own standalone menu bar icon Permission none required L2 sensitive (warns the user at install time) Good for one-shot actions (copy IP, toggle a setting) persistently showing state (a countdown, a live value) Icon uses the menu item’s icon you set it, SF Symbols supported Most plugins want the first one. Reach for a standalone icon only when you need to keep a value visible — the user gets an extra menu bar icon out of it, which is also what makes the L2 permission worth asking for.
Permission: L2 sensitive
Methods
app.statusbar.create(config?)
Creates a standalone menu bar icon.
Parameters:
config(table, optional):title(string, optional) - Display texticon(string, optional) - Icon, supports:- File path: automatically scaled to 18x18
"sf:symbol.name": SF Symbol name (e.g."sf:star.fill")
tooltip(string, optional) - Tooltip text on hover
Returns: string, error - Menu bar icon ID
-- Text only
local id = app.statusbar.create({title = "MyPlugin"})
-- Icon only
local id = app.statusbar.create({icon = "sf:bolt.fill"})
-- Text + icon + tooltip
local id = app.statusbar.create({
title = "⚡",
icon = self:getInstallPath() .. "/icon.png",
tooltip = "My Plugin Status Bar"
})
app.statusbar.delete(id)
Deletes a menu bar icon.
Parameters:
id(string) - Icon ID
Returns: boolean, error
app.statusbar.deleteAll()
Deletes all menu bar icons for the current plugin.
Returns: boolean
app.statusbar.setTitle(id, title)
Updates the text of a menu bar icon.
Parameters:
id(string) - Icon IDtitle(string) - New text
Returns: boolean, error
app.statusbar.setTitle(id, "Running")
app.statusbar.setIcon(id, icon)
Updates the image of a menu bar icon.
Parameters:
id(string) - Icon IDicon(string) - Icon path or"sf:symbol.name"
Returns: boolean, error
app.statusbar.setIcon(id, "sf:checkmark.circle.fill")
app.statusbar.setTooltip(id, tooltip)
Updates the tooltip text of a menu bar icon.
Parameters:
id(string) - Icon IDtooltip(string) - New tooltip text
Returns: boolean, error
app.statusbar.setMenu(id, items, callback?)
Sets the dropdown menu for a menu bar icon.
Parameters:
id(string) - Icon IDitems(array<table>) - Menu item array, each item:title(string) - Menu item textid(string, optional) - Menu item identifier (passed to the callback; defaults to title)icon(string, optional) - SF Symbol:"sf:symbol.name"enabled(boolean, optional) - Whether the item is enabled, default truechecked(boolean, optional) - Whether to show a checkmarkseparator(boolean, optional) - When true, creates a separator linechildren(array<table>, optional) - Submenu items
callback(function, optional) - Menu item click callback, receivesmenuItemIdparameter
Returns: boolean, error
app.statusbar.setMenu(id, {
{title = "Start", id = "start", icon = "sf:play.fill"},
{title = "Pause", id = "pause", icon = "sf:pause.fill"},
{separator = true},
{title = "Settings", id = "settings", children = {
{title = "Option A", id = "optA", checked = true},
{title = "Option B", id = "optB"},
}},
{separator = true},
{title = "Quit", id = "quit"},
}, function(menuItemId)
app.log.info("Clicked: " .. menuItemId)
if menuItemId == "quit" then
app.statusbar.delete(id)
end
end)
app.statusbar.list()
Lists menu bar icons for the current plugin.
Returns: array<table> - Each item contains:
id(string) - Icon IDtitle(string, optional) - Current texttooltip(string, optional) - Current tooltip
Description
- Each plugin can have up to 3 menu bar icons
- Icon files are automatically scaled to 18x18 pixels
- Setting
isTemplate = trueautomatically supports dark/light mode - Menu bar icons are automatically removed when the plugin is unloaded
- Calling
setMenu()repeatedly replaces the previous menu and callback
Examples
Pomodoro Timer
local mbId = nil
local timerId = nil
local remaining = 25 * 60 -- 25 minutes
function MyPlugin:init()
mbId = app.statusbar.create({
title = "🍅 25:00",
tooltip = "Pomodoro Timer"
})
self:updateMenu()
end
function MyPlugin:updateMenu()
app.statusbar.setMenu(mbId, {
{title = "Start", id = "start"},
{title = "Reset", id = "reset"},
{separator = true},
{title = "Close", id = "close"},
}, function(itemId)
if itemId == "start" then
self:startTimer()
elseif itemId == "reset" then
self:resetTimer()
elseif itemId == "close" then
app.statusbar.delete(mbId)
end
end)
end
function MyPlugin:startTimer()
if timerId then return end
timerId = app.timer.every(1, function()
remaining = remaining - 1
if remaining <= 0 then
app.timer.cancel(timerId)
timerId = nil
app.statusbar.setTitle(mbId, "🍅 Done!")
app.dock.bounce("critical")
app.notification.show("Pomodoro", "Time's up! Take a break")
else
local min = math.floor(remaining / 60)
local sec = remaining % 60
app.statusbar.setTitle(mbId, string.format("🍅 %02d:%02d", min, sec))
end
end)
end
function MyPlugin:resetTimer()
if timerId then
app.timer.cancel(timerId)
timerId = nil
end
remaining = 25 * 60
app.statusbar.setTitle(mbId, "🍅 25:00")
end