Skip to content

Examples

This page explains a few complete Lua widget patterns. For official packages, dependencies, and local examples, use Widget Packages And Examples.

If you are just starting out, read First Widget before using these as templates.

Toggle widget

local enabled = false
local toggle

local function render()
    toggle:set({
        icon = {
            string = enabled and "󰄬" or "󰄱",
            color = enabled and "#30d158" or "#ff453a",
        },
        label = {
            string = enabled and "ON" or "OFF",
            color = enabled and "#30d158" or "#ff453a",
        },
    })
end

toggle = easybar.add(easybar.kind.item, "toggle_test", {
    position = "right",
    order = 1,
})

toggle:subscribe(easybar.events.forced, function()
    render()
end)

toggle:subscribe(easybar.events.mouse.clicked, function()
    enabled = not enabled
    render()
end)

render()

Official Homebrew package

packages/brew/widget.lua is a complete example of a stateful popup widget. It:

  • checks formulae and casks with brew outdated
  • exposes Update and Upgrade actions as clickable popup children
  • runs Homebrew commands asynchronously so other widgets remain responsive
  • changes Update to Cancel while an operation is active
  • returns directly to the idle actions after cancellation while preserving the last known package list
  • writes command diagnostics to brew-widget.log under the configured EasyBar logging directory

The widget is intentionally more extensive than the snippets on this page. Use it as a reference for command chaining, cancellation, structured state rendering, popup rows, error presentation, and bounded file logging.

Use the inbox-only packages/inbox-brew/widget.lua variant to publish outdated formulae, casks, Homebrew warnings, and command errors into the native inbox. It supports refresh, brew update, individual or complete upgrades, and cancellation while an update or upgrade is running. Install either brew or inbox-brew, not both.

Official GitLab package

packages/gitlab/widget.lua shows the open issues and merge requests assigned to the authenticated user. It works with GitLab.com and private GitLab Self-Managed or Dedicated instances through the official glab CLI. Use the inbox-only packages/inbox-gitlab/widget.lua variant to publish the same work items into EasyBar's shared native inbox.

The equivalent inbox-only GitHub publisher is packages/inbox-github/widget.lua. Both publishers use EasyBar's native item URL handling, preserve the last valid snapshot when a refresh fails, and publish service update times for the inbox's default timestamp sorting. Their generic validation, bounded-error, and ISO-8601 parsing functions live in packages/shared/inbox.lua. The service publishers remain complete package entrypoints, while the shared helper is documented under Reusable Modules. Use examples/inbox-demo/widget.lua to preview inbox grouping, severities, Markdown, unread state, and actions without external services.

Install glab, authenticate the instance, and make the CLI and host available to GUI-launched EasyBar sessions:

brew install glab
glab auth login --hostname gitlab.example.com
[app.env]
PATH = "/usr/local/bin:/opt/homebrew/bin:/usr/bin:/bin:/usr/sbin:/sbin"
GITLAB_HOST = "https://gitlab.example.com"

The gitlab package manifest declares its shared-library dependency and external glab requirement. The widget refreshes every five minutes, orders assigned work by its most recent update, opens an item when its popup row is clicked, and provides Refresh and Open GitLab actions in its native right-click menu. GITLAB_HOST is optional for GitLab.com.

Clock widget

local clock

clock = easybar.add(easybar.kind.item, "clock", {
    position = "right",
    order = 10,
    interval = 60,
    icon = "􀐫",
    label = os.date("%H:%M"),
    on_interval = function()
        clock:set({
            label = os.date("%H:%M"),
        })
    end,
})

Native context menu widget

examples/context-menu.lua shows a native macOS right-click menu with actions, a separator, checked state, a submenu, and dynamic menu replacement. See Native Context Menus for the full API and right-click precedence rules.

examples/popup-context-menu.lua attaches both interaction surfaces to one anchor. Hovering shows status in a popup, while right-clicking opens a native menu with an action and checked mode submenu. The example also shows how one render function keeps popup content, anchor content, and menu checkmarks synchronized. The popup uses EasyBar's native hover tracking, so it remains open while moving from the anchor into the popup without custom mouse.entered or mouse.exited handlers.

Widget-relative image asset

local github = easybar.add(easybar.kind.item, "github", {
    icon = {
        color = easybar.theme.ref.text,
        image = {
            path = easybar.asset("github.svg"),
            size = 16,
        },
    },
})

easybar.asset() resolves relative to the Lua entrypoint, so the example expects github.svg beside the widget file. Prefix the path with @/ to resolve it from the configured widgets directory instead:

easybar.asset("@/assets/github.svg")

This is useful for user-managed widgets that share root assets. Installable packages normally keep assets inside their own package directory and use file-relative paths. easybar.asset(...) rejects absolute paths; an already absolute path may still be assigned directly to image.path.

Inline SVG image

local github_svg = [[
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
    <path d="..." />
</svg>
]]

local github = easybar.add(easybar.kind.item, "github", {
    icon = {
        color = easybar.theme.ref.text,
        image = {
            svg = github_svg,
            size = 16,
        },
    },
})

Inline SVG is useful for small, self-contained widgets. Set either path or svg, never both. Without an icon color, SVG images keep their original colors; setting icon.color applies the same template tint used for file-backed images. Inline SVG does not sandbox a widget: widget files remain trusted local code.