FragmentFragment

Handle

Reactive controller bound to a specific UI Instance path.

Client Only

This class is only available when running on the client.

A Handle is the core primitive of Fragment. It binds a renderer function to a specific UI Instance resolved via a path from PlayerGui, and re-runs that renderer whenever its subscribed data or state changes.

Handles manage:

  • Rendering and effect lifecycles
  • Local reactive state slots
  • Derived and memoized values
  • Async state helpers
  • Named signal connections
  • Store and Context subscriptions
  • Diffing containers for dynamic children

Render-cycle methods

These methods are only active inside a renderer or an Effect callback. Calling them outside produces a warning and does nothing.

Effect(fn)

Registers a side-effect that runs after every render. If fn returns a cleanup function, it is called before the next render.

Prop

Type

Example:

ClockHandle.luau
Handle.Effect(function()
    local conn = RunService.Heartbeat:Connect(function()
        element.Text = os.date("%H:%M:%S")
    end)

    return function()
        conn:Disconnect() 
    end
end)

Action(actionName, fn)

Registers a named action callable from outside the renderer via the handle.

Prop

Type

Example:

ShopHandle.luau
Handle.Action("Toggle", function(state: boolean) 
    element.Visible = state
end)

-- From anywhere:
Fragment.getHandle("Shop"):Toggle(true)

Once(fn)

Runs fn exactly once on the first render.

Prop

Type

Example:

IndexWindow.luau
Handle.Once(function()
    for index, mutation in ipairs(MutationsAndRarity.Mutations) do
        table.insert(tabs, { Name = mutation.Name, Tier = index }) 
    end
end)

Connect(connName, signal, callback)

Binds a named connection slot to an RBXScriptSignal.

Prop

Type

Example:

ShopHandle.luau
local closeBtn = element.TopFrame.Close :: TextButton

Handle.Connect("Close", closeBtn.Activated, function() 
    Fragment.getHandle("Shop"):Toggle(false)
end)

RegisterContainer(frame)

Returns a persistent Container for frame that diffs children across renders.

Prop

Type

Available inside Effects

RegisterContainer can be called both at the top level of a renderer and inside Effect callbacks.

Example:

LeaderboardHandle.luau
local list = Handle.RegisterContainer(element.ScrollFrame) 

for i, entry in ipairs(data.entries) do
    local row = Fragment.useComponent("LeaderboardRow", { name = entry.name, score = entry.score })
    list.UpsertChild(entry.id, row)
end

Bindings

Bindings are slots that persist across renders. They must be called in the same order on every render.

handle:bind(initialValue)

Creates a reactive state slot inside the renderer. The slot is initialised once on the first render.

Prop

Type

Returns:

  • getter: () -> any — reads the current value
  • setter: (any) -> () — updates the value and queues a re-render

Example:

TabsHandle.luau
local tabIndex, setTabIndex = Handle:bind(1) 

for i, tab in ipairs(tabs) do
    local live = container.UpsertChild(tab.name, Assets.Tab:Clone())
    live.Active = tabIndex() == i

    Handle.Connect("Tab_" .. tab.name, live.Activated, function()
        setTabIndex(i)
    end)
end

handle:derive(fn, deps)

Returns a getter whose value is recomputed only when deps changes.

Prop

Type

Example:

IndexWindow.luau
local getFiltered = Handle:derive(function() 
    return superDuperTableFilterFunction(allItems, function(item) 
        return item.tier == currentTier 
    end) 
end, { currentTier }) 

for _, item in ipairs(getFiltered()) do
    -- render item
end

handle:hold(fn, deps)

Returns a stable function reference. The same function object is returned as long as deps is unchanged.

Prop

Type

Example:

ShopHandle.luau
local onBuy = Handle:hold(function() 
    purchaseItem(selectedItem()) 
end, { selectedItem() }) 

Handle.Connect("BuyBtn", buyButton.Activated, onBuy)

handle:await(fn, deps?)

Runs fn asynchronously and returns a status table. Triggers a re-render when the operation settles.

Non-blocking

await uses task.spawn internally and never yields the renderer. The renderer immediately receives a "pending" status table and re-renders again once the operation resolves.

Prop

Type

status is one of:

  • "pending" — operation in progress
  • "resolved" — completed successfully, value holds the result
  • "rejected" — failed, error holds the message

Example:

ShopHandle.luau
local inventory = Handle:await(function() 
    return InventoryService:FetchAsync() 
end, { store.lastUpdated }) 

if inventory.status == "pending" then
    element.Spinner.Visible = true
    return
end

element.Spinner.Visible = false

if inventory.status == "resolved" then
    for _, item in ipairs(inventory.value) do
        -- render item
    end
end

handle:pull(ctx)

Subscribes the handle to a Context and returns the live value table.

Prop

Type

Example:

ShopHandle.luau
local win = Handle:pull(WindowContext) 

element.Visible = win.active == "Shop"

Other methods

Disconnect(connName)

Manually disconnects a named connection outside of a render.

Prop

Type

Example:

Handle:Disconnect("Close")

Render()

Manually triggers a full render pass.

Prop

Type

Example:

Fragment.getHandle("HUD"):Render()

On this page