Rex.define API

API reference for wrapping and enhancing existing Roblox UI instances with Rex functionality.

Last updated: 6/29/2025
Version: 0.2.0

The Rex.define() function allows you to wrap existing Roblox UI instances with Rex’s reactive functionality, enabling incremental migration from traditional UI to Rex-powered reactive UI.

Rex.define(instance: Instance | string): (props?: RexProps) -> RexElement

Wraps an existing Roblox Instance with Rex functionality, allowing you to add reactive properties, event handlers, and children management.

Parameters:

  • instance: Instance | string — The Roblox Instance to wrap, or a string name to find a child by name

Returns: Function that accepts props and returns a wrapped RexElement

Usage:

-- Direct instance reference
local enhancedFrame = Rex.define(existingFrame) {
    BackgroundColor3 = Color3.fromRGB(50, 50, 60),
    onClick = function() print("Clicked!") end
}

-- String name reference (finds child in parent context)
Rex.define("ChildButton") {
    Text = "Enhanced Button",
    onClick = handleClick
}

Property Override

Any properties specified in props will override the existing instance properties while preserving unspecified properties:

Rex.define(studioButton) {
    -- Override Studio-set properties
    BackgroundColor3 = Color3.fromRGB(100, 150, 255),
    Text = "New Text",
    
    -- Add reactive properties
    TextColor3 = isEnabled:map(function(enabled)
        return enabled and Color3.new(1, 1, 1) or Color3.new(0.5, 0.5, 0.5)
    end)
}

Event Attachment

Add Rex event handlers to existing instances using the same event system as regular Rex elements:

Rex.define(existingButton) {
    onClick = function() playerScore:increment() end,
    onHover = function() setHovered(true) end,
    onLeave = function() setHovered(false) end
}

Children Management

Define children as a mix of existing child references and new Rex components:

Rex.define(parentFrame) {
    children = {
        -- Reference existing children by name
        Rex.define("ExistingLabel") {
            Text = dynamicText,
            TextColor3 = Color3.fromRGB(255, 255, 255)
        },
        
        -- Add new Rex components
        Rex("TextButton") {
            Text = "New Button",
            Size = UDim2.fromScale(1, 0.2),
            onClick = handleNewAction
        }
    }
}

Instance Resolution

Direct Instance References

When passing an Instance directly, Rex.define will use it immediately:

local myFrame = workspace.UI.MainFrame
Rex.define(myFrame) { BackgroundColor3 = Color3.new(1, 0, 0) }

String Name Resolution

When passing a string, Rex.define will find the child within the parent context:

Rex.define(parentFrame) {
    children = {
        Rex.define("ButtonChild") { -- Looks for parentFrame:FindFirstChild("ButtonChild")
            onClick = handleClick
        }
    }
}

Compatibility

Preserve Existing Properties

Only specified properties are overridden; all other properties remain unchanged:

-- If button originally had: Text="Original", Size=UDim2.fromOffset(100,50)
Rex.define(button) {
    BackgroundColor3 = Color3.new(1, 0, 0) -- Only this changes
    -- Text and Size remain "Original" and UDim2.fromOffset(100,50)
}

Reparenting Behavior

Rex.define avoids unnecessary reparenting. If the instance already has the correct parent, it won’t be moved:

-- ✅ Good - no reparenting needed
Rex.define(frameAlreadyInCorrectParent) { ... }

-- ⚠️ Warning - will reparent if necessary but issues warning
Rex("ScreenGui") {
    children = {
        Rex.define(frameFromDifferentParent) { ... }
    }
}

Error Handling

Rex.define provides helpful error messages for common issues:

  • Missing child: Clear error with available child names
  • Invalid instance type: Type validation with suggestions
  • No parent context: Guidance for string name resolution
-- Error: Child "MissingButton" not found in parent "MainFrame"
-- Available children: Title, Content, Footer
Rex.define("MissingButton") { ... }

Performance Considerations

  • Reconciliation: Defined elements participate in Rex’s efficient diffing system
  • Reactive bindings: Only reactive properties create subscriptions
  • Memory management: Automatic cleanup when elements are destroyed

Examples

Basic Enhancement

-- Enhance a Studio-created button with reactive behavior
local enhancedButton = Rex.define(studioButton) {
    Text = buttonText, -- Reactive state
    BackgroundColor3 = isPressed:map(function(pressed)
        return pressed and Color3.fromRGB(200, 200, 200) or Color3.fromRGB(100, 150, 255)
    end),
    onClick = function()
        isPressed:toggle()
        onButtonClick()
    end
}

Complex UI Enhancement

local function EnhancedDialog()
    local isVisible = Rex.useState(true)
    local message = Rex.useState("Hello!")
    
    return Rex.define(dialogFrame) {
        Visible = isVisible,
        children = {
            Rex.define("TitleLabel") {
                Text = "Enhanced Dialog"
            },
            Rex.define("MessageLabel") {
                Text = message
            },
            Rex.define("CloseButton") {
                onClick = function()
                    isVisible:set(false)
                end
            }
        }
    }
end