Create a Component
Build reusable template-backed renderers with full reactive access.
A Component packages a template Instance and its rendering logic into a reusable unit. Where a Handle is bound to one specific UI path, a Component is cloned on demand and can be used inside any Handle or other Component.
Components receive the calling Handle as a third argument, giving them full access to Effect, Connect, RegisterContainer, stores, contexts, and hooks — exactly the same as the Handle's own renderer.
Add a template to your assets
Place the template Instance you want to clone somewhere accessible in ReplicatedStorage. For example:
ReplicatedStorage/
└── Assets/
└── UI/
└── ItemCardTemplate ← your Frame hereCreate the Component module
Add a ModuleScript inside your Components/ folder.
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Fragment = require(ReplicatedStorage.Fragment)
local Component = Fragment.newComponent("ItemCard", {
"ReplicatedStorage", "Assets", "UI", "ItemCardTemplate"
})
return Component(function(element: Frame, props: {
Id: string,
Name: string,
Price: number,
}, handle: any)
element.Name = props.Id
element:FindFirstChild("NameLabel").Text = props.Name
element:FindFirstChild("PriceLabel").Text = `🪙 {props.Price}`
end)newComponent takes:
- name — unique identifier used with
Fragment.useComponent - path — child names traversed from
gameroot to the template Instance
Register it with the structured loader
Add your Components folder to Fragment.load. Components are loaded after Contexts and Hooks but before Handles, so they can reference anything that came before them.
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Fragment = require(ReplicatedStorage.Fragment)
Fragment.load({
Stores = script.Parent.Stores,
Contexts = script.Parent.Contexts,
Hooks = script.Parent.Hooks,
Components = script.Parent.Components,
Handles = script.Parent.Handles,
})Use it inside a Handle
Call Fragment.useComponent to clone and render the Component, then hand the result to a Container.
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Fragment = require(ReplicatedStorage.Fragment)
local Handle = Fragment.newHandle("Shop", { "HUD", "Shop", "MainFrame" })
return Handle(function(element: Frame)
local store = Fragment.useStore("Shop")
local data = store.getData()
local grid = Handle.RegisterContainer(element.ItemGrid)
for _, item in ipairs(data.items) do
local card = Fragment.useComponent("ItemCard", {
Id = item.id,
Name = item.displayName,
Price = item.price,
})
grid.UpsertChild(item.id, card)
end
end)Adding reactive behaviour
Because the Handle is forwarded to the Component renderer, you can register Effects, Connections, and anything else you would use in a Handle.
return Component(function(element: Frame, props: {
Id: string,
Name: string,
Price: number,
}, handle: any)
element.Name = props.Id
element:FindFirstChild("NameLabel").Text = props.Name
element:FindFirstChild("PriceLabel").Text = `🪙 {props.Price}`
handle.Connect("Buy_" .. props.Id, element.BuyBtn.Activated, function()
ShopService:PurchaseAsync(props.Id)
end)
end)Use unique connection names
Connections are stored on the Handle, not the Component. When the same Component is used multiple times in the same Handle, include the item's unique ID in the connection name — e.g. "Buy_" .. props.Id — to avoid one slot overwriting another.
Subscribing to a Store
return Component(function(element, props, handle)
local store = Fragment.useStore("PlayerData")
local data = store.getData()
element.Text = `🪙 {data.coins}`
end)Subscribing to a Context
local WindowContext = require(path.to.Contexts.WindowContext)
return Component(function(element, props, handle)
local win = handle:pull(WindowContext)
handle.Connect("Close_" .. props.windowName, element.Activated, function()
win.close(props.windowName)
end)
end)Using a Hook
local useToggle = require(path.to.Hooks.useToggle)
return Component(function(element, props, handle)
local isOn, toggle = useToggle(props.initialState)
element.Toggle.Active = isOn()
handle.Connect("Toggle_" .. props.id, element.Toggle.Activated, function()
toggle()
end)
end)Nested Components and Containers
A Component can register its own Container and nest further Components inside it.
return Component(function(element, props, handle)
local list = handle.RegisterContainer(element.ItemList)
for _, item in ipairs(props.items) do
local row = Fragment.useComponent("ItemRow", {
id = item.id,
name = item.name,
})
list.UpsertChild(item.id, row)
end
end)For the full Component API see the Component reference.