Browse the docs

menuBarItems

Adds a section to Switchboard's menu bar menu that your extension fills and updates.

Details #

Switchboard lives in the menu bar. The menuBarItems point adds a section to the menu that opens from its icon. Each section has a title, an optional symbol and a list of rows. Rows can be commands, ticked choices, separators or submenus.

The section is yours to describe, and the engine draws it. When the menu opens, the engine asks your handler what to show. When the person chooses a row, the engine tells your handler which one.

Declare it in switchboard.json under adds.menuBarItems:

{
  "adds": {
    "menuBarItems": [
      { "id": "water", "title": "Water", "icon": "drop", "refreshSeconds": 300 }
    ]
  }
}

And implement it:

import { defineExtension, menuBarItem } from '@switchboard/sdk';

export default defineExtension({
  menuBarItems: [
    menuBarItem('water', {
      build: async (ctx) => ({ title: 'Water: 3', items: [{ id: 'add', title: 'Add a glass' }] }),
      click: async (entryId, ctx) => { /* entryId is 'add' */ },
    }),
  ],
});

Gotchas #

  • build must answer within 3 seconds, or the section shows its last answer greyed out. click has 10 seconds.

  • ctx.menu.update only works for an item this extension declared.

  • Rows with an empty id or no title are dropped. Keep ids stable so ticks and clicks stay with the right row.

  • The menu is read as it opens. Do not do slow work in build; keep the number somewhere cheap (ctx.storage) and read it.

  • No permission is needed to define a section. The handler needs permissions only for what it does itself.

  • Unknown keys in an entry are refused.

A complete extension using this point can be downloaded from the Full example section and edited: a daily water tally with commands, a ticked submenu and a live title.

Manifest fields #

FieldRequiredWhat it is
idyesLowercase letters, digits and . _ -, up to 64 characters, starting with a letter. Unique in the list.
titleyes1 to 80 characters. Shown until your handler answers, and greyed if it stops answering.
descriptionnoUp to 1000 characters.
iconno1 to 200 characters. The name of a symbol, used when the handler gives none.
refreshSecondsnoA whole number from 1 to 3600. How often the engine asks build again. Without it, only when the menu opens.

What the handler gets and returns #

build(ctx) returns the section's state:

  • title: the section's title (up to 120 characters).

  • icon: a symbol name.

  • items: up to 50 rows. A row has an id and a title, and optionally enabled: false to grey it, checked: true to tick it, children for a submenu (up to three levels), or separator: true to draw a line.

With no items, the title is a single clickable row, and a click arrives with the item's own id.

click(entryId, ctx) runs when a row is chosen. It returns nothing. The engine asks build again afterwards. To show the change at once from inside click, or from a timer, call ctx.menu.update(itemId, state) with the same shape build returns.

Full example #

See also #