Skip to content

menu ​

Create menu pages and manage buttons, toggles, sliders, and lists.

Page builders ​

Create a page with menu.root(title) → MenuPage. A script may create multiple roots. They appear beneath that script's file controls in Settings → LUA.

page:submenu ​

Callback: None; creates a child page.

text
page:submenu(name [, description])

Returns: MenuPage

page:button ​

Callback: No arguments.

text
page:button(name, callback [, description])

Returns: MenuControl

page:toggle ​

Callback: New boolean value.

text
page:toggle(name, initial, callback [, description])

Returns: MenuControl

page:number ​

Callback: New number.

text
page:number(name, initial, minimum, maximum, step, callback [, description])

Returns: MenuControl

page:list ​

Callback: New one-based integer index, then its label string.

text
page:list(name, items, initial_index, callback [, description])

Returns: MenuControl

page:separator ​

Callback: No callback; creates a labeled divider.

text
page:separator(name)

Returns: MenuControl

Names, descriptions, and list labels use the standard 4,096-byte text validation. A number control requires finite values, a valid initial value within its bounds, and a positive step. Number controls use the menu's two-decimal display. Lists require a dense sequence of 1–512 string labels and an initial index in 1..#items.

Menu actions are queued and run on the script owner. Callbacks are not called automatically just because a control is created: initialize the variables that represent your feature state yourself.

Control methods ​

control:get ​

Returns the toggle's boolean or a number/list control's numeric value.

text
control:get()

control:set ​

Updates an editable control without invoking its callback.

text
control:set(value)

control:rename ​

Changes this control's label.

text
control:rename(text)

control:description ​

Changes this control's description.

text
control:description(text)

control:remove ​

Removes this control and its action.

text
control:remove()

set() accepts a boolean for a toggle, a finite in-range value for a number, or a whole one-based in-range index for a list. A number's set() value is not snapped to its step. Buttons and separators do not have an editable value; calling set() on them fails. Do not rely on their internal get() value.

MenuPage exposes the builders above, not the MenuControl methods. There is no public page rename/remove method. Do not directly construct MenuPage or MenuControl values.

After removal, a control must no longer be used for value or label updates. Reload invalidates the old script's handles. Control state is not automatically persisted in Harmony configurations. API v2 does not expose script-menu translation, global search integration, text inputs, or a custom control-style API.

Complete menu example ​

lua
local root = menu.root("Display settings")
local appearance = root:submenu("Appearance", "Adjust this script's overlay.")
local enabled = true
local textSize = 18
local themeIndex = 1
local themes = { "Pearl", "Amber", "Mint" }

appearance:separator("Overlay")

local toggle = appearance:toggle("Enabled", enabled, function(value)
    enabled = value
end)

local size = appearance:number("Text size", textSize, 12, 32, 1, function(value)
    textSize = value
end)

local theme = appearance:list("Theme", themes, themeIndex, function(index, label)
    themeIndex = index
    util.log("Selected " .. label)
end)

appearance:button("Restore defaults", function()
    enabled = true
    textSize = 18
    themeIndex = 1

    -- set() does not invoke the callbacks, so update local state explicitly.
    toggle:set(enabled)
    size:set(textSize)
    theme:set(themeIndex)
end)

local colors = {
    draw.color(235, 235, 245),
    draw.color(245, 185, 70),
    draw.color(120, 225, 180)
}

script.on_tick(function()
    if enabled then
        draw.text(32, 120, themes[themeIndex], colors[themeIndex], textSize)
    end
end)