Skip to content

UI Controls

github-actions[bot] edited this page Jul 4, 2026 · 4 revisions

UI Controls & Options Panel

The UI module (RGXUI) provides widget factories for common interface controls and a full options panel builder with tab system and scroll container.


Widget Factories

UI:CreateSlider(parent, opts)Frame

Create a horizontal slider control bound to a storage table — it saves and restores its value.

Parameters:

Parameter Type Required Default Description
parent Frame Yes Parent frame
opts.key string Yes Storage key the slider reads/writes
opts.storage table No {} Table holding storage[key] (usually your db)
opts.label string No key Label text
opts.min / opts.max number No 0 / 100 Range
opts.step number No 1 Step increment
opts.default number No min Value when storage is empty; Reset target
opts.suffix string No "" Appended to the displayed value, e.g. "%"
opts.width number No 200 Track width
opts.progress boolean No true Show the brand-colored fill behind the thumb; false for a bare track
opts.onChange function No onChange(value)

The thumb re-positions itself on OnShow, so a slider built on a panel that is still hidden (login/load) lands at the correct spot the first time the panel opens — no set/reset needed.

local slider = UI:CreateSlider(parent, {
    key = "scale", storage = MyAddonDB,
    label = "Scale", min = 50, max = 150, step = 5,
    default = 100, suffix = "%",
    onChange = function(val) MyFrame:SetScale(val / 100) end,
})

UI:CreateToggle(parent, opts)Frame

Create a checkbox toggle bound to a storage table.

Parameters:

Parameter Type Required Default Description
parent Frame Yes Parent frame
opts.key string Yes Storage key
opts.storage table No {} Table holding storage[key]
opts.label string No key Label text beside the checkbox
opts.default bool No Value when storage is empty; Reset target
opts.onChange function No onChange(checked)
local toggle = UI:CreateToggle(parent, {
    key = "notifications", storage = MyAddonDB,
    label = "Enable Notifications", default = true,
    onChange = function(checked) ... end,
})

UI:CreateLabel(parent, opts)FontString

Create a styled label using the theme's named sizes and colors.

Parameters:

Parameter Type Required Default Description
parent Frame Yes Parent frame
opts.text string Yes Label text
opts.size string No "normal" "small" | "normal" | "large"
opts.color string No "normal" "normal" | "muted" | "accent" | "red" | "green" | "yellow" (theme tokens)
opts.width number No Enables word wrap at this width — required for long text, which otherwise renders past the parent frame's edge on a single line
opts.justify string No "LEFT" Horizontal justify (only with width)
local hint = UI:CreateLabel(parent, {
    text = "A long descriptive sentence that needs to wrap inside the panel.",
    size = "small", color = "muted", width = 340,
})

UI:CreateColorPicker(parent, opts)table

Create a color swatch control that opens the ColorPicker on click.

Parameters:

Parameter Type Required Default Description
parent Frame Yes Parent frame
opts.label string No Label text
opts.value table No {1,1,1,1} Initial color {r,g,b,a}
opts.onChange function No onChange(r, g, b, a) callback

Returns: { frame, swatch, label }

local cp = UI:CreateColorPicker(parent, {
    label = "Background Color",
    value = {0.1, 0.1, 0.2, 1.0},
    onChange = function(r, g, b, a)
    myFrame:SetBackdropColor(r, g, b, a)
    end,
})

UI:CreateColorPickerCard(parent, opts)Frame

The embeddable color picker — the full SV-box + hue-bar + preview + hex inline as a card, for placing directly in an options tab (instead of the popup swatch). Multi-instance with its own state; bound to storage[key] = {r,g,b}. Click or drag the SV box and hue bar to pick.

Parameter Type Required Default Description
opts.key string No Storage key holding {r,g,b}
opts.storage table No {} Table the widget reads/writes
opts.default table No white {r,g,b} when storage is empty
opts.width number No 220 Card width
opts.onChange function No onChange(r, g, b) on every change

Returns the widget frame, with :SetColor(r,g,b) / :GetColor().

local card = UI:CreateColorPickerCard(container, {
    key = "accent", storage = MyAddonDB, default = { r = 1, g = 0, b = 0 },
    onChange = function(r, g, b) MyAddon:SetAccent(r, g, b) end,
})

UI:CreateColorSettingControl(parent, opts)table

Color swatch + label bound to a saved variable. Changes write directly to storage[key].

Parameters:

Parameter Type Required Description
parent Frame Yes Parent frame
opts.label string Yes Label text
opts.storage table Yes Saved variable table
opts.key string Yes Key within storage
opts.onChange function No Additional change callback
local ctrl = UI:CreateColorSettingControl(parent, {
    label = "Bar Color",
    storage = MyAddonDB.profile,
    key = "barColor",
})

UI:CreateStatusBarDropdown(parent, opts)table

Statusbar texture selection dropdown. Delegates to the Textures module.

Parameters:

Parameter Type Required Description
parent Frame Yes Parent frame
opts.label string No Label text
opts.value string No Initial statusbar name
opts.onChange function No onChange(barName) callback

UI:CreateFontDropdown(parent, opts)table

Font family selection dropdown. Delegates to the Fonts module.

Parameters:

Parameter Type Required Description
parent Frame Yes Parent frame
opts.label string No Label text
opts.value string No Initial font name
opts.onChange function No onChange(fontName) callback

UI:CreateFontSettingControl(parent, opts)table

Font dropdown + reset button bound to storage[key]. Delegates to the Fonts module.

Parameters:

Parameter Type Required Description
parent Frame Yes Parent frame
opts.label string Yes Label text
opts.storage table Yes Saved variable table
opts.key string Yes Key within storage
opts.onChange function No Additional change callback

Options Panel Builder

UI:CreateOptionsPanel(name, opts)panel

Create a full options panel with tab system, scroll container, and header.

Parameters:

Parameter Type Required Default Description
name string Yes Panel name (used as frame name)
opts.title string No name Title text in header
opts.subtitle string No "" Subtitle text
opts.width number No 800 Panel width
opts.height number No 600 Panel height
opts.version string No Version string shown in header
opts.author string No Author string shown in header
opts.website string No Website URL shown in header

Returns: Panel object with methods below.

Panel Methods

Providing tabs

Tabs are supplied at creation through opts.tabs; each content(container) builder runs once, the first time its tab is shown:

local panel = UI:CreateOptionsPanel({
    addonName = "MyAddon",
    tabs = {
        { text = "General", content = function(container)
            UI:CreateToggle(container, { key = "enabled", label = "Enabled", storage = MyAddonDB })
            UI:CreateSlider(container, { key = "scale", label = "Scale", min = 50, max = 150, storage = MyAddonDB })
        end },
        { text = "Colors", content = function(container)
            UI:CreateColorPicker(container, { key = "primary", label = "Primary Color", storage = MyAddonDB })
        end },
    },
})

Extending another addon's panel — RGX:AddOptionsTab(addonName, text, builder[, geom])

Register extra tabs onto an addon's panel by name, before it is built (i.e. at file-parse time, from a second file). The declarative panel builder appends them after the addon's own options tabs, so a bundled dev/test suite can live on the addon's own panel instead of a separate window. geom optionally hints panel width/height/maxPerRow; the largest hint across all registrations wins. Panels are not rebuilt after creation, so this must run before the addon's ADDON_LOADED.

RGX:AddOptionsTab("MyAddon", "Debug", function(container)
    UI:CreateButton(container, "Dump State", 120, 24, DumpState)
end, { maxPerRow = 5 })

RGX:GetAddon(name) returns the addon object (with .panel) if you need it.

panel:Open()

Open the panel and navigate to it in Interface Options:

panel:Open()

panel:SelectTab(index)

Switch to a tab by 1-based index:

panel:SelectTab(2) -- switch to Fonts tab

panel:SelectTabByName(name)

Switch to a tab by its name:

panel:SelectTabByName("Fonts")

panel:InvalidateAllTabs()

Mark all tabs for rebuild. Next time each tab is shown, its buildFn will be re-executed:

panel:InvalidateAllTabs()

panel:Refresh()

Force-refresh the currently visible tab:

panel:Refresh()

Complete Options Panel Example

local UI = RGX:GetUI()

local panel = UI:CreateOptionsPanel("MyAddonOptions", {
    title = "My Addon",
    subtitle = "v1.0.0 by Me",
    width = 800,
    height = 600,
})

panel:AddTab("General", function(container)
    UI:CreateToggle(container, {
        label = "Enable Addon",
        value = MyAddonDB.profile.enabled,
        onChange = function(v) MyAddonDB.profile.enabled = v end,
    })
    UI:CreateSlider(container, {
        label = "Update Interval",
        min = 0.1,
        max = 5.0,
        step = 0.1,
        value = MyAddonDB.profile.interval,
        onChange = function(v) MyAddonDB.profile.interval = v end,
    })
end)

panel:AddTab("Appearance", function(container)
    UI:CreateFontDropdown(container, {
        label = "Font Family",
        value = MyAddonDB.profile.fontFamily,
        onChange = function(v) MyAddonDB.profile.fontFamily = v end,
    })
    UI:CreateSlider(container, {
        label = "Font Size",
        min = 8,
        max = 24,
        step = 1,
        value = MyAddonDB.profile.fontSize,
        onChange = function(v) MyAddonDB.profile.fontSize = v end,
    })
    UI:CreateColorPicker(container, {
        label = "Text Color",
        value = MyAddonDB.profile.textColor,
        onChange = function(r, g, b, a)
        MyAddonDB.profile.textColor = {r, g, b, a}
        end,
    })
    UI:CreateStatusBarDropdown(container, {
        label = "Bar Texture",
        value = MyAddonDB.profile.barTexture,
        onChange = function(v) MyAddonDB.profile.barTexture = v end,
    })
end)

-- Register with WoW
InterfaceOptions_AddCategory(panel.frame)

-- Open from slash command
SLASH_MYADDON1 = "/myaddon"
SlashCmdList.MYADDON = function()
    panel:Open()
end

Layout Notes

  • Controls are positioned automatically within the scroll container
  • Each control is anchored below the previous one
  • Use container (the scroll child) as the parent for all controls
  • The scroll container handles overflow automatically
  • Tab content is built lazily on first show and cached unless invalidated

Clone this wiki locally