> ## Documentation Index
> Fetch the complete documentation index at: https://docs.rebind.gg/llms.txt
> Use this file to discover all available pages before exploring further.

# rb.ui

> Declare a script's settings panel and read its values.

`rb.ui` declares a settings panel that Rebind shows in the script's **Options**
tab, reads and writes the values the user sets there, and shows notifications.
A script reaches for it when a hotkey, a speed or a switch should change without
editing the code.

This script declares a toggle and a slider and logs their values when it starts:

```luau theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
-- rebind: min_sdk=3.9.0 name=example version=1.0.0
local cfg = rb.ui.schema({
  enabled = rb.ui.toggle(true),
  speed = rb.ui.slider(50, { min = 1, max = 100, suffix = "%" }),
})

rb.on("start", function()
  rb.log.info("enabled:", cfg.enabled, "speed:", cfg.speed)
end)
```

![The Options tab of snippet-expander.lua with Controls and Expansion groups](https://mintcdn.com/rebind/mk4-exzrQ1Bh6kZJ/images/app/config-panel.png?fit=max\&auto=format\&n=mk4-exzrQ1Bh6kZJ\&q=85\&s=1827b5fb7f69ad75fe989a21cce16d34)

The Options tab of a running script, with toggles, a keybind, a select and sliders in two groups.

| Signature | Value type |
| - | - |
| `rb.ui.schema(descriptors: { [string]: any }) -> UiProxy` | a proxy: `cfg.key` reads, `cfg.key = v` writes |
| `rb.ui.toggle(default: boolean, opts: ToggleOpts?) -> any` | boolean switch |
| `rb.ui.slider(default: number, opts: SliderOpts?) -> any` | number; range `0` to `100` unless set |
| `rb.ui.keybind(default: string, opts: KeybindOpts?) -> any` | key name or chord such as `"LAlt+1"`, or `"<key>@<device id>"` once the user restricts it to one device |
| `rb.ui.select(default: string, choices: { string }, opts: SelectOpts?) -> any` | one of `choices` |
| `rb.ui.text(default: string, opts: TextOpts?) -> any` | string |
| `rb.ui.color(default: string, opts: ColorOpts?) -> any` | hex string such as `"#ff0000"`; strip the `#` before comparing with `rb.screen.pixel_hex` or passing to `rb.screen.search_color` |
| `rb.ui.list(default: { string }, opts: ListOpts?) -> any` | an array of strings in the order the user entered them, `{}` when empty; `min_sdk` 3.15.0 |
| `rb.ui.button(label: string, opts: ButtonOpts?) -> any` | `nil`, or the [look](#buttons) the script gave it; `min_sdk` 3.19.0 |
| `rb.ui.get(id: string) -> any` | the value of `id`, or `nil` |
| `rb.ui.set(id: string, value: any) -> ()` | writes a value |
| `rb.ui.get_all() -> { [string]: any }` | every value |
| `rb.ui.get_schema() -> { any }` | the schema descriptors |
| `rb.ui.notify(text: string, variant: string?) -> ()` | shows a notification; `"info"` (default), `"success"`, `"warning"` or `"error"` |

| Option | Applies to | Meaning |
| - | - | - |
| `label` | all | display label; default is the key |
| `tooltip` | all | hover text |
| `group` | all | section header |
| `tab` | all | tab name |
| `show_if` | all | shown only while the named toggle is on, or while `select_id:value` matches |
| `min`, `max`, `step`, `suffix` | slider | range, increment, unit label |
| `placeholder`, `max_length` | text, list | hint and character limit (for a list, per entry) |

Fields appear in the order the constructors were called. Saved values load
before `rb.ui.schema` returns, so top-level code already reads them, and every
change is saved, keyed by the script's file path. A schema entry that is not
built with a constructor raises `UI.Schema entry '<key>' is not a UI component`.

A keybind field saves the next key, button or wheel step while it is listening.
Hold a modifier before it to save a chord such as `LAlt+1` or `LShift+WheelUp`;
a modifier pressed and released alone is saved by itself. A plain left click is
never saved, so clicking the box again stops listening; a left click behind a
held modifier is saved as a chord such as `LCtrl+LAlt+Mouse1`. A wheel step is
a trigger for [`rb.bind`](https://docs.rebind.gg/reference/sdk/bind) only: it never reaches a `down`
handler or `rb.input.is_down`. A chord is a trigger for
[`rb.bind`](https://docs.rebind.gg/reference/sdk/bind); a script that compares the value with a key
name in a handler gets the whole string.

Every keybind field shows an **Only from this device** switch. Turning it on
waits for the next press and saves the key as a
[pinned key](https://docs.rebind.gg/reference/sdk/bind.md); the switch is off in software mode, where no device is known. A default is always a plain
key: one containing `@` raises
`UI.Schema entry '<key>': a keybind default is a plain key`.

## rb.ui.list

**Needs:** `min_sdk=3.15.0`.

A list shows its entries as rows with a remove button and an add field. Enter
adds an entry after trimming it, and a blank entry or one already in the list is
ignored. The script reads and writes a plain table of strings:

```luau theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
-- rebind: min_sdk=3.15.0 name=example version=1.0.0
local cfg = rb.ui.schema({
  apps = rb.ui.list({ "chrome", "firefox" }, {
    label = "Run only in these apps",
    placeholder = "app name",
  }),
})

local function in_listed_app()
  local process = rb.system.window().process:lower()
  for _, app in cfg.apps do
    if process:find(app:lower(), 1, true) then
      return true
    end
  end
  return false
end

rb.bind("F8", function()
  rb.log.info("matched")
end, { when = in_listed_app })
```

Rules for a list:

* The default must be an array of strings, or `{}`. Anything else raises
  `UI.Schema entry '<key>': UI.List default must be an array of strings`.
* `cfg.key = value` and `rb.ui.set` take an array of strings. Any other value,
  such as a string, a number, or an array holding a non-string, raises an error
  that names the key and leaves the list as it was. Assigning `{}` empties it.
* A table with extra non-numeric keys loses those keys, and a table with a gap
  is cut at the first gap, because only the array part is stored.
* A saved value that is not an array of strings, including one saved from the
  panel while the script was stopped, is ignored when the script loads, and the
  default is used.
* `max_length` limits an entry in the panel only. A script can write a longer
  entry.

## Buttons

**Needs:** `min_sdk=3.19.0`.

`rb.ui.button(label, opts)` adds a button to the schema. The **Options** tab
shows it with its label, or the `text` of the look the script set, and whether
that look is `active`. Nothing in the
**Options** tab presses a button, so its handlers do not run from there.
`cfg.key = { text = "LIVE", active = true }` sets the look while the script
runs, `cfg.key = nil` restores the declared one, and a look is never saved.
Assigning anything other than a table raises an error that names the button.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.