Script UI Configuration API
The Configuration Schema system allows scripts to define custom UI forms for user input. This provides a rich set of components for creating complex configuration interfaces.
Schema Structure
config_schema = {
version = "1.0",
layout = {
-- Root layout component
}
}
Special Configuration Fields
When using a tab-based layout, the system automatically adds special fields to track UI state:
active_tab(string): The label of the currently selected tab (e.g., "General", "Advanced")active_tab_index(number): The zero-based index of the currently selected tab (0, 1, 2, etc.)
These fields are automatically set when the Start button is pressed and can be accessed in your script's on_start function.
function on_start(config)
-- Access which tab was selected
logger:info("Active tab: " .. tostring(config.active_tab))
logger:info("Tab index: " .. tostring(config.active_tab_index))
-- Use it to adjust behavior
if config.active_tab == "Quick Start" then
-- User started from Quick Start tab
use_preset_defaults()
elseif config.active_tab == "Advanced" then
-- User started from Advanced tab
use_custom_settings(config)
end
end
Note: These fields are only available when using the tabs layout type at the root level. Non-tabbed layouts will not have these fields.
Layout Components
Section
Groups related components together with optional header.
{
type = "section",
label = "General Settings",
description = "Configure basic script options",
children = {
-- Child components
}
}
Tabs
Creates a tabbed interface for organizing settings.
{
type = "tabs",
children = {
{
type = "section",
label = "Tab 1",
children = { -- Tab content }
},
{
type = "section",
label = "Tab 2",
children = { -- Tab content }
}
}
}
Grid
Arranges components in a grid layout.
{
type = "grid",
props = {
columns = 2 -- Number of columns
},
children = {
-- Components arranged in grid
}
}
VStack / HStack
Vertical or horizontal stack layouts.
{
type = "vstack", -- or "hstack"
children = {
-- Stacked components
}
}
Input Components
Text Input
{
type = "text",
id = "username",
label = "Username",
description = "Enter your character name",
props = {
placeholder = "Enter text...",
default = "DefaultValue"
}
}
Button
{
type = "button",
id = "btn_id",
label = "Click Me",
props = {
variant = "primary",
size = "md",
data_component_id = "table_id" -- Optional: clears associated table's profile data on click
}
}
function script:on_button_clicked(btn_id, values)
-- Handle button click event
return config:get_schema(values)
end
Button Properties:
| Property | Type | Required | Description |
|---|---|---|---|
variant | string | No | Button style: "primary", "secondary", etc. Default: "primary" |
size | string | No | Button size: "sm", "md", or "lg". Default: "md" |
data_component_id | string | No | When provided, clicking this button will clear the profile configuration data associated with the specified table component ID. This is useful for "Clear" or "Reset" buttons that should remove saved table data (like saved items in a dynamic table). The table component with the matching id will have its profile data removed when this button is clicked |
Button Click Handler:
Buttons trigger the on_button_clicked callback in your script. When a button has data_component_id set, the associated table's profile data is automatically cleared before the callback is invoked.
Number Input
{
type = "number",
id = "quantity",
label = "Quantity",
description = "How many items to process",
props = {
min = 1,
max = 1000,
step = 1,
default = 100
}
}
Checkbox
{
type = "checkbox",
id = "use_bank",
label = "Use Bank",
description = "Enable banking between trips",
props = {
default = true
}
}
Select (Dropdown)
{
type = "select",
id = "location",
label = "Location",
description = "Choose mining location",
props = {
options = {
{value = "varrock", label = "Varrock Mine"},
{value = "lumbridge", label = "Lumbridge Mine"},
{value = "falador", label = "Falador Mine"}
},
default = "varrock",
placeholder = "Select a location..."
}
}
Slider
{
type = "slider",
id = "speed",
label = "Action Speed",
description = "Delay between actions in milliseconds",
props = {
min = 100,
max = 5000,
step = 50,
default = 1000
}
}
Multi-Select
{
type = "multi_select",
id = "items",
label = "Items to Collect",
description = "Select multiple items",
props = {
options = {
{value = "iron", label = "Iron ore"},
{value = "coal", label = "Coal"},
{value = "gold", label = "Gold ore"}
},
default = {"iron", "coal"}
}
}
Data Components
Table
{
type = "table",
id = "item_prices",
label = "Price Configuration",
props = {
keys = {"item"}, -- Use "item" column to generate unique row keys
columns = {
{key = "item", label = "Item", type = "string"},
{key = "price", label = "Price", type = "number"},
{key = "enabled", label = "Enabled", type = "boolean"}
},
data = {
{item = "Iron ore", price = 100, enabled = true},
{item = "Coal", price = 150, enabled = false}
},
selected = {
{item = "Iron ore", price = 100, enabled = true},
{item = "Coal", price = 150, enabled = false}
}, -- Selected rows as full objects
selection_mode = "multiple", -- "single", "multiple", or "none"
sortable = true
}
}
Table Properties:
| Property | Type | Required | Description |
|---|---|---|---|
columns | array | Yes | Column definitions with key, label, optional type, optional width, and optional component (see below) |
data | array | Yes | Array of row objects. Each row should have properties matching the column key values |
keys | array | No | Array of column key values used to generate a unique identifier for each row. If not provided, the system will attempt to use an id field from row data. The row key is generated by joining the values of these specified columns with underscores (e.g., if keys = {"name", "level"}, a row with name = "Iron" and level = 15 will have key "Iron_15") |
selected | array or object | No | Pre-selected rows. For multiple selection, use an array of row objects; for single selection, use a single row object. The system matches rows by comparing the generated keys from the keys property |
selection_mode | string | No | Selection mode: "single", "multiple", or "none". Default: "single" |
sortable | boolean | No | Enable column sorting. Default: false |
Column Properties:
| Property | Type | Required | Description |
|---|---|---|---|
key | string | Yes | The property name in the row data to display in this column |
label | string | No | Display label for the column header |
type | string | No | Data type hint: "string", "number", or "boolean" |
width | string | No | Column width (e.g., "200px", "150px") |
component | object | No | Custom component to render in cells of this column (see Column Component Rendering below) |
Column Component Rendering:
Columns can render custom components instead of simple text values. When a column has a component property, that component will be rendered in each cell of that column. The component has access to all row data through the values object.
Key Behaviors:
-
Selection Requirement: Components in table cells are automatically disabled if the row is not selected. Only selected rows allow editing of cell components. This ensures that users can only modify data for rows they've explicitly chosen.
-
Row Data Access: Components in table cells receive the full row data merged with any updates made to the selected row. For example, if a row has
{name = "Iron ore", price = 100, quantity = 10}, the component can access all these values through thevaluesobject. -
Component IDs: If a column component has an
id, it will be used as-is. If a column component does not have anid, the system automatically uses the column'skeyas the component ID. This ensures each component has a unique identifier for value tracking. -
Value Updates: When a component in a cell changes its value, the system automatically updates the selected row object. The updated row is then stored in the table's selection, preserving all changes made through cell components.
-
Fallback Behavior: If a column doesn't have a
componentproperty, it will fall back to simple text rendering usingrow[col.key].
{
type = "table",
id = "item_config",
label = "Item Configuration",
props = {
keys = {"name"}, -- Use "name" column to generate row keys
columns = {
{key = "name", label = "Item Name"}, -- Simple text rendering
{
key = "quantity",
label = "Quantity",
component = {
type = "number",
-- No id specified, so "quantity" will be used as the component id
props = {
min = 1,
max = 1000,
default = 1
}
}
},
{
key = "enabled",
label = "Enabled",
component = {
type = "checkbox",
props = {
default = true
}
}
},
{
key = "priority",
label = "Priority",
component = {
id = "item_priority", -- Explicit ID
type = "select",
props = {
options = {
{value = "low", label = "Low"},
{value = "medium", label = "Medium"},
{value = "high", label = "High"}
},
default = "medium"
}
}
}
},
data = {
{name = "Iron ore", quantity = 10, enabled = true, priority = "high"},
{name = "Coal", quantity = 5, enabled = false, priority = "low"}
},
selection_mode = "multiple"
}
}
Important Notes for Column Components:
-
Selection-Based Editing: Users must select a row (via checkbox/radio or row click) before they can edit components in that row's cells. Unselected rows have disabled components. This prevents accidental edits and ensures users explicitly choose which rows to configure.
-
Value Persistence: Changes made to cell components are stored directly in the selected row object. When the configuration is submitted, the
selectedarray contains the updated row objects with all cell component changes applied. The originaldataarray remains unchanged. -
Row Key Generation: The
keysproperty in table props specifies which column values are used to create a unique identifier for each row. For example, ifkeys = {"name", "level"}, a row withname = "Iron ore"andlevel = 15will have the key"Iron ore_15". This key is used internally to match rows during selection and updates. -
Selection Format: The
selectedproperty should contain full row objects (not just IDs or keys). The system matches rows by comparing the generated keys. For example:
-- Multiple selection
selected = {
{name = "Iron ore", quantity = 10, enabled = true},
{name = "Coal", quantity = 5, enabled = false}
}
-- Single selection
selected = {name = "Iron ore", quantity = 10, enabled = true}
- Component ID Auto-Assignment: If a column component doesn't specify an
id, the system automatically uses the column'skeyas the component ID. This ensures each component has a unique identifier while keeping the schema simple.
Example: Table with Mixed Column Types
{
type = "table",
id = "trading_config",
label = "Trading Configuration",
props = {
columns = {
{key = "item", label = "Item"}, -- Simple text
{
key = "min_price",
label = "Min Price",
component = {
type = "number",
props = {
min = 0,
max = 1000000,
default = 0
}
}
},
{
key = "max_price",
label = "Max Price",
component = {
type = "number",
props = {
min = 0,
max = 1000000,
default = 1000000
}
}
},
{
key = "action",
label = "Action",
component = {
type = "select",
props = {
options = {
{value = "buy", label = "Buy"},
{value = "sell", label = "Sell"},
{value = "skip", label = "Skip"}
},
default = "buy"
}
}
}
},
keys = {"item"}, -- Use "item" column to generate row keys
data = {
{item = "Iron ore", min_price = 50, max_price = 150, action = "buy"},
{item = "Coal", min_price = 100, max_price = 200, action = "sell"}
},
selection_mode = "multiple"
}
}
List
{
type = "list",
id = "tasks",
label = "Task Queue",
props = {
items = {
{id = 1, label = "Mine iron"},
{id = 2, label = "Bank ores"},
{id = 3, label = "Repeat"}
}
}
}
Display Components
Text Display (Read-only)
{
type = "text_display",
id = "info",
label = "Information",
props = {
text = "This is read-only informational text."
}
}
Image
{
type = "image",
id = "preview",
label = "Location Preview",
props = {
url = "https://example.com/image.png",
width = 200,
height = 150
}
}
Common Component Properties
All components support these optional properties:
{
id = "unique_identifier", -- Required for input components
label = "Display Label", -- Component label
description = "Helper text", -- Description/tooltip
visible = true, -- Boolean or conditional (see below)
enabled = true, -- Boolean or conditional
props = { -- Component-specific properties
-- Component-specific options
}
}
Conditional Visibility
Components can be shown/hidden based on other field values:
{
type = "number",
id = "max_price",
label = "Maximum Price",
visible = {
field = "use_price_limit",
operator = "equals",
value = true
}
}
Operators:
| Operator | Description |
|---|---|
"equals" | Field equals value |
"not_equals" | Field does not equal value |
"contains" | Field contains value (for strings/arrays) |
"greater_than" | Field is greater than value |
"less_than" | Field is less than value |
"in" | Field value is in array |
Validation
Add validation rules to ensure valid configuration:
{
type = "number",
id = "quantity",
label = "Quantity",
validation = {
rule = {
type = "range",
min = 1,
max = 1000
},
message = "Quantity must be between 1 and 1000"
}
}
Validation Types:
| Type | Description |
|---|---|
"required" | Field must have a value |
"range" | Number must be within min/max |
"custom" | Custom Lua validator function |
Dynamic Configuration Callbacks
Scripts can implement callbacks to update configuration dynamically:
-- Called when configuration values change
function on_config_changed(values)
-- values is a table of current configuration
-- Return updated schema based on current values
return config_schema
end
Examples
Complete Configuration Schema Example
config_schema = {
version = "1.0",
layout = {
type = "tabs",
children = {
-- General Settings Tab
{
type = "section",
label = "General",
children = {
{
type = "vstack",
children = {
{
type = "select",
id = "location",
label = "Mining Location",
description = "Choose where to mine",
props = {
options = {
{value = "varrock_east", label = "Varrock East Mine"},
{value = "varrock_west", label = "Varrock West Mine"},
{value = "mining_guild", label = "Mining Guild"}
},
default = "varrock_east"
}
},
{
type = "multi_select",
id = "ores",
label = "Ores to Mine",
description = "Select which ores to mine",
props = {
options = {
{value = "iron", label = "Iron"},
{value = "coal", label = "Coal"},
{value = "mithril", label = "Mithril"}
},
default = {"iron"}
}
},
{
type = "checkbox",
id = "use_bank",
label = "Use Banking",
description = "Bank ores when inventory is full",
props = {default = true}
}
}
}
}
},
-- Advanced Settings Tab
{
type = "section",
label = "Advanced",
children = {
{
type = "grid",
props = {columns = 2},
children = {
{
type = "number",
id = "min_delay",
label = "Minimum Delay (ms)",
props = {min = 50, max = 5000, default = 600}
},
{
type = "number",
id = "max_delay",
label = "Maximum Delay (ms)",
props = {min = 50, max = 5000, default = 1200}
}
}
},
{
type = "slider",
id = "antiban_level",
label = "Anti-ban Level",
description = "Higher values add more randomization",
props = {min = 1, max = 10, step = 1, default = 5}
},
{
type = "checkbox",
id = "enable_breaks",
label = "Enable Breaks",
props = {default = false}
},
{
type = "number",
id = "break_interval",
label = "Break Interval (minutes)",
visible = {
field = "enable_breaks",
operator = "equals",
value = true
},
props = {min = 5, max = 120, default = 30}
}
}
}
}
}
}
-- Handle configuration changes
function on_config_changed(values)
logger:info("Configuration updated: " .. tostring(values.location))
-- Update schema dynamically if needed
return config_schema
end
Table with Clear Button Example
This example demonstrates using a button with data_component_id to clear saved table data:
config_schema = {
version = "1.0",
layout = {
type = "vstack",
children = {
{
type = "section",
label = "Item Selection",
children = {
{
type = "table",
id = "selected_items",
label = "Items to Process",
description = "Select items from the available list. All items are selected by default.",
props = {
keys = {"name"}, -- Use "name" column to generate row keys
columns = {
{key = "name", label = "Item Name", width = "200px"},
{key = "level", label = "Required Level", width = "150px"},
{key = "xp", label = "XP", width = "100px"}
},
data = {
{name = "Iron ore", level = 15, xp = 35},
{name = "Coal", level = 30, xp = 50},
{name = "Mithril ore", level = 55, xp = 80},
{name = "Adamantite ore", level = 70, xp = 95},
{name = "Runite ore", level = 85, xp = 125}
},
selection_mode = "multiple"
}
},
{
type = "hstack",
children = {
{
type = "button",
id = "refresh_items",
label = "Refresh Items",
props = {
variant = "primary"
}
},
{
type = "button",
id = "clear_saved",
label = "Clear Saved Items",
props = {
variant = "secondary",
data_component_id = "selected_items" -- Clears profile data for this table
}
}
}
}
}
}
}
}
}
-- Handle button clicks
function script:on_button_clicked(btn_id, values)
if btn_id == "refresh_items" then
-- Refresh the table data dynamically
return update_table_with_new_items()
elseif btn_id == "clear_saved" then
-- The data_component_id prop already cleared the profile data
-- Just update the schema to reflect the cleared state
return config_schema
end
return config_schema
end
Key Features Demonstrated:
data_component_idon Button: The "Clear Saved Items" button hasdata_component_id = "selected_items", which means clicking it will:- Remove any saved profile configuration data for the
selected_itemstable - Allow the table to reset to its default state
- Useful when users want to clear custom items they've added to the table
- Remove any saved profile configuration data for the
Best Practices
- Configuration Validation: Always validate user input and provide clear error messages through validation rules.
- Conditional UI: Use conditional visibility to simplify complex configurations by showing/hiding relevant options.
- Descriptive Labels: Provide clear labels and descriptions for all configuration options.
- Layout Organization: Use tabs and sections to organize complex configurations into logical groups.
- Tab Selection Tracking: Use the
active_tabfield to detect which tab users started from and adjust default behaviors accordingly.
Related APIs
- Script UI Configuration Guide - Learn how to use Script UI Configuration in your scripts