app.statusbar - Menu Bar Icon API
Creates and manages standalone macOS menu bar (status bar) icons and menus.
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