Custom widgets
Description #
Custom widgets let you run any executable script and display its output in the bar. The output format is derived from and inspired by the xbar plugin API. Any script that produces valid xbar-compatible output will work in a-bar without modification.
A script runs periodically, writes to standard output, and a-bar parses the result into bar text and an optional dropdown menu. This means you can write plugins in any language: bash, Python, Ruby, Node.js, Swift, or anything else that can print to stdout.
How the output is parsed #
The output of your script is split into two sections by the first --- line.
- Lines before
---are called header lines. They cycle in the bar one at a time, rotating according to the widget's Cycle Duration setting. - Lines after
---appear in a native dropdown menu when the widget is clicked. - If there is no
---line, all output lines cycle as header lines and no dropdown is shown.
Any line that consists of exactly --- and nothing else acts as a separator:
- The first
---in the output marks the boundary between header lines and menu items. - Any subsequent
---line inside the menu section inserts a visual separator between menu items.
Empty lines are ignored.
Parameters #
Each line can carry optional parameters by appending a pipe character | followed by key=value pairs, separated by additional pipes.
Text to display | param1=value1 | param2=value2Parameter names and values are trimmed of surrounding whitespace. Values may be wrapped in single or double quotes. The pipe-splitting respects quoted strings, so a value containing a pipe character can be quoted safely.
The following parameters are supported.
Visual parameters #
| Parameter | Type | Default | Description |
|---|---|---|---|
color |
string | inherited | Text color. Accepts named colors (red, blue, green, orange, purple, cyan, cadetblue, etc.), hex values (#RGB, #RRGGBB, #RRGGBBAA), and rgb() / rgba() functions. |
font |
string | bar font | Font name to use for this item's text. |
size |
number | bar font size | Font size in points. |
length |
integer | none | Truncate the title to this many characters and append .... The full text is shown in a tooltip. |
trim |
true/false | true | Whether to strip leading and trailing whitespace from the title. |
image |
base64 string | none | Attach an image to the menu item. The value must be the image data encoded as a base64 string. Displayed at 16x16 points. |
templateImage |
base64 string | none | Same as image but the image is treated as a template, meaning macOS renders it in the appropriate color for the current menu appearance. Recommended for icons that should respect dark/light mode. |
Interaction parameters #
| Parameter | Type | Default | Description |
|---|---|---|---|
href |
URL string | none | Open this URL in the default browser when the item is clicked. Accepts https://, http://, and custom URL schemes. |
shell |
path string | none | Path to an executable to run when the item is clicked, e.g. /bin/bash. |
param1 ... paramN |
string | none | Arguments passed to the shell executable in order. Use param1, param2, param3, etc. |
terminal |
true/false | true | When shell is set, controls whether the script runs inside a visible terminal window. Set to false to run silently in the background. |
refresh |
true/false | false | Re-run the widget script after the action (shell command or href) completes. |
disabled |
true/false | false | Grey out the item and make it non-interactive. Useful for section labels or static information. |
alternate |
true/false | false | Mark this item as an alternate to the previous one. While the Option key is held, this item replaces the previous one in the dropdown. |
key |
shortcut string | none | Assign a keyboard shortcut to the menu item. See the Key shortcuts section below. |
dropdown |
true/false | true | When set to false, this header line is excluded from the dropdown entirely and only cycles in the bar. |
Key shortcuts #
The key parameter accepts a combination of modifier names and a key character joined by +.
Supported modifier names: CmdOrCtrl, OptionOrAlt, shift, ctrl, super.
Supported special key names: return, escape, tab, space, plus, up, down, f1 through f12.
Examples:
Open settings | key=CmdOrCtrl+,
Quit | key=CmdOrCtrl+q
Submit | key=shift+returnSubmenu nesting #
Inside the dropdown menu section, lines that start with -- (two dashes) are placed one level deeper as submenu items. Each additional pair of dashes adds one more level of nesting.
Top-level item
--First submenu item
--Second submenu item
----Nested inside second submenuSubmenu nesting only applies to lines in the menu section (after ---). Dashes at the start of a header line are treated as literal text.
Submenus support all the same parameters as top-level items.
Widget settings #
Custom widget options are configured in the Custom tab in Settings.
Name: Display name. Must be unique because it is used as the target for AppleScript commands.Command: The shell command or script path to run. The output is interpreted as xbar-compatible markup.Refresh interval: How often to re-run the script in seconds. Default is 60.Cycle duration: How long each header line is shown before rotating to the next one, in seconds. Only relevant when the script produces more than one header line. Default is 4.Background color: Optional background color for the widget pill. Accepts theme color names (main,mainAlt,minor,accent,red,green,yellow,orange,blue,magenta,cyan) or any CSS color string.Active: Whether the widget is currently visible in the bar.Hide when empty: Hide the widget entirely if the script produces no output.
Writing a script #
Any executable that prints to standard output will work. The recommended approach is to use a shebang line so the script is self-contained.
#!/usr/bin/env bash
echo "Hello"Set the Command field to the full path of the script:
/Users/you/scripts/hello.shOr invoke the interpreter directly if the script is not executable:
bash /Users/you/scripts/hello.shIf your script depends on tools installed by Homebrew or other package managers, add their directories to PATH explicitly, because a-bar does not source your shell profile:
#!/usr/bin/env bash
export PATH="/opt/homebrew/bin:/usr/local/bin:$PATH"
brew services list | grep running | wc -l | xargs echo "Homebrew services:"a-bar passes the following environment variable to every script:
| Variable | Value |
|---|---|
PATH |
Inherits the app PATH, prepended with /usr/local/bin and /opt/homebrew/bin. |
Interactions #
- Click a widget that has a dropdown to open the native menu.
- Click a menu item that has
href=to open the URL. - Click a menu item that has
shell=to run the command. - Items with
refresh=truewill re-run the script after the action completes. - Widgets can be refreshed, toggled, hidden, or shown via AppleScript. See the Automation page.
AppleScript #
Custom widgets respond to the same AppleScript commands as other widgets. Use the widget's Name as the target.
Refresh a specific widget:
tell application "a-bar" to refresh "My Widget"Toggle a widget:
tell application "a-bar" to toggle "My Widget"Show or hide a widget:
tell application "a-bar" to show "My Widget"
tell application "a-bar" to hide "My Widget"Example: World Clock #
The following script demonstrates header line cycling, color-coded items, submenus, a clipboard action, and a manual refresh item.
#!/usr/bin/env bash
ZONES=(
"America/New_York:New York"
"Europe/London:London"
"Europe/Paris:Paris"
"Asia/Tokyo:Tokyo"
"Australia/Sydney:Sydney"
)
# Header lines -- one per timezone, cycled in the bar
for entry in "${ZONES[@]}"; do
tz="${entry%%:*}"
city="${entry##*:}"
time=$(TZ="$tz" date "+%H:%M")
echo "$city $time"
done
echo "---"
echo "World Clock | disabled=true color=#888888"
echo "---"
for entry in "${ZONES[@]}"; do
tz="${entry%%:*}"
city="${entry##*:}"
time=$(TZ="$tz" date "+%H:%M")
day=$(TZ="$tz" date "+%a %d %b")
offset=$(TZ="$tz" date "+%Z (UTC%z)")
hour=$(TZ="$tz" date "+%H")
if [ "$hour" -ge 9 ] && [ "$hour" -lt 18 ]; then
color="#4CAF50"
elif [ "$hour" -ge 18 ] && [ "$hour" -lt 22 ]; then
color="#FF9800"
else
color="#5C6BC0"
fi
echo "$city $time | color=$color"
echo "--$day | disabled=true"
echo "--$offset | disabled=true"
echo "--Copy to clipboard | shell=/bin/bash param1=-c param2=\"echo -n '${city}: ${time}' | pbcopy\" terminal=false refresh=false"
echo "---"
done
echo "---"
echo "Refresh | key=CmdOrCtrl+R | refresh=true"Settings for this widget: Refresh interval 60, Cycle duration 4.