Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Roblox/roact/llms.txt

Use this file to discover all available pages before exploring further.

When a component needs to produce several sibling elements, the instinct is often to wrap them all inside a container Frame. That wrapper becomes a real Roblox Instance, however — it sits in the hierarchy, breaks layout components like UIListLayout, and clutters the object tree with structure that serves no purpose other than satisfying Roact’s single-root requirement. Fragments solve this cleanly: Roact.createFragment lets a component return a collection of elements that each become direct children of the component’s parent, with no wrapper Instance ever created.

The Problem: Unwanted Wrapper Instances

Suppose you are building a team roster UI. A TeamList component owns a Frame with a UIListLayout so the children stack vertically. You extract the label rows into a separate TeamLabels component, but that component needs to return two TextLabels — so you wrap them in a Frame.
-- TeamList renders the layout container
local function TeamList(props)
    return Roact.createElement("Frame", {
        -- Props for Frame...
    }, {
        Layout = Roact.createElement("UIListLayout", {
            -- Props for UIListLayout...
        }),
        ListItems = Roact.createElement(TeamLabels),
    })
end

-- TeamLabels wraps both labels in a Frame just to satisfy the single-root rule
local function TeamLabels(props)
    return Roact.createElement("Frame", {
        -- Props for Frame...
    }, {
        RedTeam = Roact.createElement("TextLabel", {
            -- Props for item...
        }),
        BlueTeam = Roact.createElement("TextLabel", {
            -- Props for item...
        }),
    })
end
The UIListLayout in TeamList only affects its direct siblings, so this extra Frame layer breaks the layout entirely. The resulting Roblox hierarchy looks like this:
Frame
└── UIListLayout
└── Frame          ← unwanted wrapper; UIListLayout ignores its children
    └── TextLabel  (RedTeam)
    └── TextLabel  (BlueTeam)
The two TextLabels are nested one level too deep and are invisible to the UIListLayout.

The Fix: Roact.createFragment

Roact.createFragment was added in Roact 1.0.0.
Roact.createFragment takes a table of named elements and returns a fragment — a lightweight object that Roact flattens into the parent’s children when mounting. No wrapper Instance is ever inserted into the DataModel.
Roact.createFragment(elements: table) -> Fragment
Do not modify the elements table after passing it to createFragment. Roact holds a reference to the table; mutating it after the fact can cause unpredictable reconciliation behaviour.
local function TeamLabels(props)
    -- A Frame is required just to group the two labels.
    -- This creates an unwanted Instance in the hierarchy.
    return Roact.createElement("Frame", {
        -- Props for Frame...
    }, {
        RedTeam = Roact.createElement("TextLabel", {
            -- Props for item...
        }),
        BlueTeam = Roact.createElement("TextLabel", {
            -- Props for item...
        }),
    })
end
Resulting hierarchy:
Frame
└── UIListLayout
└── Frame
    └── TextLabel  (RedTeam)
    └── TextLabel  (BlueTeam)
The UIListLayout does not apply to the labels because they are not direct siblings of the layout component.
Because the labels are now direct children of the outer Frame, the UIListLayout stacks them exactly as intended.

When to Use Fragments vs. a Real Container

SituationRecommendation
Children need a layout component (UIListLayout, UIGridLayout) that lives in the same parentUse a fragment — avoid an extra wrapper that breaks the layout
The grouping boundary is a meaningful visual container (background, padding, clipping)Use a real Frame — the container genuinely belongs in the hierarchy
A component is composing a list and the caller controls the layoutUse a fragment so the caller’s layout sees all items as siblings
You need Roblox properties like Size, BackgroundColor3, or ClipsDescendants on the grouping nodeUse a real element — fragments have no Instance and carry no properties
Fragments are purely an organizational tool for Roact; they have no runtime cost and no corresponding Roblox object. Use them whenever you find yourself adding a Frame whose only purpose is to satisfy the single-root rule.

Build docs developers (and LLMs) love