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 text
    • icon (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 ID
  • title (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 ID
  • icon (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 ID
  • tooltip (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 ID
  • items (array<table>) - Menu item array, each item:
    • title (string) - Menu item text
    • id (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 true
    • checked (boolean, optional) - Whether to show a checkmark
    • separator (boolean, optional) - When true, creates a separator line
    • children (array<table>, optional) - Submenu items
  • callback (function, optional) - Menu item click callback, receives menuItemId parameter

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 ID
  • title (string, optional) - Current text
  • tooltip (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 = true automatically 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
Developer Documentation
User Guide
Getting Started Script Menus FAQ
Script Development
Development Guide
Plugin Development
Quick Start Development Guide Example Plugins
API Reference
Overview API Query Plugin Info Logging Finder Context Plugin Settings Internationalization
UI & Interaction
Dialog Progress Notification Chooser WebView Status Bar Dock
Files & Paths
File Operations Path Utilities Finder Actions Trash Extended Attributes Metadata File Watcher
Data Formats
JSON Plist CSV XML PDF Image
Text & Encoding
String Regex Date & Time Color Crypto
System
Shell Commands Process Application System Info AppleScript Shortcuts
System Info
Network Power/Battery Screen/Appearance Audio Bluetooth Location
Network
HTTP WebSocket URL
Input & Clipboard
Keyboard Mouse Hotkey Clipboard Window
Storage
SQLite Keychain UserDefaults
Media
OCR QR Code
Utilities
Archive UTI Share Timer Wake Lock Thread