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:
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:
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:
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:
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:
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)
endBindings
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:
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)
endhandle:derive(fn, deps)
Returns a getter whose value is recomputed only when deps changes.
Prop
Type
Example:
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
endhandle:hold(fn, deps)
Returns a stable function reference. The same function object is returned as long as deps is unchanged.
Prop
Type
Example:
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,valueholds the result"rejected"— failed,errorholds the message
Example:
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
endhandle:pull(ctx)
Subscribes the handle to a Context and returns the live value table.
Prop
Type
Example:
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()