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)