> For the complete documentation index, see [llms.txt](https://docs.xeutrino.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.xeutrino.com/api-reference/ui.md).

# UI construction

Each script owns its own submenu tree under **Lua Scripts**. Build your UI at the top of your script, before entering the main loop. Every option is keyed by a string `id` you choose; that `id` is how you later read or write its state with [`get_opt`](/api-reference/option-state.md#get_optid--integer) / [`set_opt`](/api-reference/option-state.md#set_optid-value).

UI calls only affect the **currently-open submenu**. `add_submenu` opens a new one; everything you add afterwards goes inside it until that scope closes.

## `add_submenu(name [, body])`

Creates a child submenu under the current one. Submenus nest to any depth.

There are two forms:

**Scoped (recommended).** Pass a function; it builds the submenu's contents and the parent scope is restored automatically when it returns.

```lua
add_submenu("Vehicle", function()
    add_button("Repair", "veh_fix")

    add_submenu("Spawner", function()      -- nested inside "Vehicle"
        add_button("Adder", "spawn_adder")
        add_button("Zentorno", "spawn_zen")
    end)

    add_checkbox("God Mode", "veh_god")    -- back in "Vehicle"
end)

add_button("Root Button", "root_btn")      -- back at the top level
```

**Imperative.** Omit the function and close the scope yourself with `end_submenu()`. Useful when the contents are built in a loop.

```lua
add_submenu("Teleports")
    for i, loc in ipairs(locations) do
        add_button(loc.name, "tp_" .. i)
    end
end_submenu()
```

| Param  | Type     | Description                                                              |
| ------ | -------- | ------------------------------------------------------------------------ |
| `name` | string   | Display label of the submenu.                                            |
| `body` | function | *Optional.* Builds the contents; the parent scope is restored on return. |

> Before, `add_submenu` entered the new submenu and never came back, so a script could only build one linear chain — every option after the first call landed in the deepest level. Both forms above nest properly.

## `end_submenu()`

Closes the submenu opened by the non-callback form of `add_submenu` and returns to its parent. Calling it at the top level is harmless. Not needed with the scoped form.

## `add_subtitle(text)`

Adds a non-interactive centered subtitle/header row to the current submenu.

| Param  | Type   | Description      |
| ------ | ------ | ---------------- |
| `text` | string | Text to display. |

## `add_button(label, id)`

Adds a clickable button. Detect a click by polling `get_opt(id) == 1` in your main loop and resetting it with `set_opt(id, 0)` after handling.

| Param   | Type   | Description                             |
| ------- | ------ | --------------------------------------- |
| `label` | string | Display text.                           |
| `id`    | string | Unique key for reading the press state. |

## `add_checkbox(label, id)`

Adds a toggle checkbox. State is `1` (checked) or `0` (unchecked).

| Param   | Type   | Description               |
| ------- | ------ | ------------------------- |
| `label` | string | Display text.             |
| `id`    | string | Unique key for the state. |

## `add_int_option(label, id, current, min, max, step)`

Adds a numeric scroller.

| Param     | Type    | Description                |
| --------- | ------- | -------------------------- |
| `label`   | string  | Display text.              |
| `id`      | string  | Unique key for the value.  |
| `current` | integer | Initial value.             |
| `min`     | integer | Minimum value (inclusive). |
| `max`     | integer | Maximum value (inclusive). |
| `step`    | integer | Increment per click.       |

## `script.inject_submenu(target_id, name)`

Like `add_submenu`, but instead of nesting under **Lua Scripts**, it injects a link to the new submenu at the bottom of one of the native C++ menus (Self, Vehicle, …). Use this to make your script feel like a first-class part of the menu.

| Param       | Type    | Description                                                                     |
| ----------- | ------- | ------------------------------------------------------------------------------- |
| `target_id` | integer | One of the `TARGET_*` constants (see [Constants](/api-reference/constants.md)). |
| `name`      | string  | Display label of the injected submenu.                                          |

```lua
script.inject_submenu(TARGET_SELF, "My Self Tools")
add_button("Heal", "btn_heal")
```

## Next

* [Option state](/api-reference/option-state.md) — reading and writing option values.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.xeutrino.com/api-reference/ui.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
