Rendering & Children API

API reference for Rex's rendering, children, fragments, and refs.

Last updated: 6/27/2025
Version: 0.2.0

Rex provides a declarative rendering system with support for children, fragments, and refs.

Rendering Elements

Elements are created using Rex(className) syntax:

local element = Rex("Frame") {
    Size = UDim2.fromScale(1, 1),
    children = {
        Rex("TextLabel") {
            Text = "Hello World"
        }
    }
}

Children

Children define the nested elements within a Rex component. They can be static, reactive, or mixed:

Static Children

children = {
    Rex("TextLabel") { Text = "Header" },
    Rex("Frame") { Size = UDim2.fromScale(1, 0.5) },
    Rex("TextButton") { Text = "Click Me" }
}

Reactive Children with :each()

The :each() method provides a clean syntax for rendering lists from array state:

local items = Rex.useState({"Apple", "Banana", "Cherry"})

children = {
    Rex("UIListLayout") {},
    items:each(function(item, index)
        return Rex("TextLabel") {
            Text = `{index}: {item}`,
            key = item, -- Important for efficient updates
            LayoutOrder = index
        }
    end)
}

Mixed Static and Reactive Children

children = {
    Rex("TextLabel") { Text = "Shopping List" }, -- Static header
    items:each(function(item, index)             -- Dynamic list items
        return ItemComponent { item = item, key = item.id }
    end),
    Rex("TextButton") { Text = "Add Item" }      -- Static footer
}

Advanced List Rendering

For complex interactive lists with state management:

local todos = Rex.useState({
    {id = 1, text = "Learn Rex", done = false},
    {id = 2, text = "Build App", done = true}
})

children = {
    Rex("UIListLayout") { Padding = UDim.new(0, 5) },
    todos:each(function(todo, index)
        return Rex("Frame") {
            Size = UDim2.new(1, 0, 0, 40),
            BackgroundColor3 = todo.done 
                and Color3.fromRGB(100, 255, 100)
                or Color3.fromRGB(255, 255, 255),
            key = tostring(todo.id), -- Use stable IDs as keys
            
            children = {
                Rex("TextLabel") {
                    Text = todo.text,
                    Size = UDim2.new(0.8, 0, 1, 0),
                    TextStrikethrough = todo.done
                },
                Rex("TextButton") {
                    Text = todo.done and "↶" or "✓",
                    Size = UDim2.new(0.2, 0, 1, 0),
                    onClick = function()
                        todos:update(function(currentTodos)
                            local newTodos = table.clone(currentTodos)
                            newTodos[index].done = not newTodos[index].done
                            return newTodos
                        end)
                    end
                }
            }
        }
    end)
}

Fragments

Group elements without wrapper instances:

Rex.Fragment {
    children = {
        Rex("Frame") {},
        Rex("TextLabel") {}
    }
}

Refs

Access instances directly:

local frameRef = Rex.useRef()
Rex("Frame") {
    [Rex.Ref] = frameRef,
    Size = UDim2.fromScale(1, 1)
}

Keyed List Rendering

Keys are essential for efficient list updates and animations. Rex uses keys to determine which elements to create, update, or remove when lists change.

Why Keys Matter

-- ❌ Without keys - inefficient, may cause issues
items:each(function(item, index)
    return ItemComponent { item = item }
end)

-- ✅ With keys - efficient reconciliation
items:each(function(item, index)
    return ItemComponent { 
        item = item, 
        key = item.id -- Use stable, unique identifier
    }
end)

Key Selection Best Practices

-- ✅ Good - stable unique IDs
todos:each(function(todo, index)
    return TodoItem { 
        todo = todo, 
        key = tostring(todo.id) -- Database ID, UUID, etc.
    }
end)

-- ✅ Acceptable - content-based keys for simple data
fruits:each(function(fruit, index)
    return FruitItem { 
        fruit = fruit, 
        key = fruit -- If fruit names are unique
    }
end)

-- ❌ Avoid - index as key (breaks on reordering)
items:each(function(item, index)
    return ItemComponent { 
        item = item, 
        key = tostring(index) -- Don't use index!
    }
end)

Performance Benefits

With proper keys, Rex can:

  • Reuse existing elements when items move
  • Preserve component state during reordering
  • Optimize animations and transitions
  • Minimize unnecessary re-renders