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.
Components are the primary unit of organisation in Roact. They accept inputs called props and return elements that describe the UI those inputs should produce. By composing small, focused components you can build complex screens without duplicating element-creation logic across your codebase.
Types of Components
Roact has three distinct component types, each suited to different situations.
Host Components
A host component is simply a string that matches the name of a Roblox class — exactly like the strings you pass to Roact.createElement in the elements guide. Examples include "Frame", "TextLabel", "ImageButton", "ScreenGui", and so on.
When Roact encounters a host component, every prop you supply is applied directly as a property on the resulting Roblox Instance. There is no Lua code involved — the mapping is 1-to-1 between your prop table and the Instance’s properties.
-- "TextLabel" is a host component.
-- Size and Text are set directly on the TextLabel Instance.
local label = Roact.createElement("TextLabel", {
Size = UDim2.new(1, 0, 0, 40),
Text = "I am a host component",
})
Function Components
A function component is a plain Lua function that accepts a props table and returns an element (or nil). Function components have no internal state and no lifecycle methods, making them ideal for pure, presentational pieces of UI.
local function Greeting(props)
return Roact.createElement("TextLabel", {
Text = "Hello, " .. props.name
})
end
You use a function component by passing the function itself as the first argument to Roact.createElement:
local hello = Roact.createElement(Greeting, {
name = "Rick James"
})
The name value is passed to Greeting inside its props argument.
Stateful Components
A stateful component is a Lua table (a class) created by calling Roact.Component:extend with a name string. Stateful components have access to mutable state and lifecycle methods, which are covered in depth in the State & Lifecycle guide.
local Greeting = Roact.Component:extend("Greeting")
function Greeting:render()
return Roact.createElement("TextLabel", {
Text = "Hello, " .. self.props.name
})
end
Inside a stateful component’s methods, props are accessed via self.props and state via self.state.
PureComponent
Roact.PureComponent works identically to Roact.Component but implements shouldUpdate automatically. It performs a shallow comparison of props and state and skips re-rendering when nothing has changed, which can improve performance for components that receive many updates with identical data.
local MyDisplay = Roact.PureComponent:extend("MyDisplay")
function MyDisplay:render()
return Roact.createElement("TextLabel", {
Text = self.props.value
})
end
Passing Props to Components
Regardless of component type, props flow from parent to child through the second argument of Roact.createElement. In a function component they arrive as the props argument; in a stateful component they are available as self.props.
-- Passing props to a function component
Roact.createElement(Greeting, {
name = "Joe"
})
-- Accessing props inside the function component
local function Greeting(props)
return Roact.createElement("TextLabel", {
Text = "Hello, " .. props.name
})
end
Using Components Inside Other Components
Because components are just Lua values, you can reference them from within any other component’s render logic. This is the primary mechanism for composition in Roact.
local function Greeting(props)
return Roact.createElement("TextLabel", {
Text = "Hello, " .. props.name
})
end
local function GreetEveryone()
return Roact.createElement("ScreenGui", {}, {
Layout = Roact.createElement("UIListLayout"),
HelloJoe = Roact.createElement(Greeting, {
name = "Joe"
}),
HelloMary = Roact.createElement(Greeting, {
name = "Mary"
})
})
end
GreetEveryone produces a ScreenGui containing a UIListLayout and two Greeting components side-by-side. Neither Greeting knows how many siblings it has or where it lives in the tree — it only knows its own props.name.
Most Roact applications have a single root component at the top of the tree that composes all other pieces as children.
Function vs Stateful: The Clock Example
The incrementing counter from the elements guide can be rewritten as either a function component or a stateful component. Both produce the same visible result.
Function Component
Stateful Component
A function component receives the current time as a prop. The caller is responsible for updating that prop (via Roact.update) whenever the time changes.local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
local Roact = require(ReplicatedStorage.Roact)
-- Function component: accepts currentTime as a prop
local function Clock(props)
local currentTime = props.currentTime
return Roact.createElement("ScreenGui", {}, {
TimeLabel = Roact.createElement("TextLabel", {
Size = UDim2.new(1, 0, 1, 0),
Text = "Time Elapsed: " .. currentTime
})
})
end
local PlayerGui = Players.LocalPlayer.PlayerGui
local currentTime = 0
local clockElement = Roact.createElement(Clock, {
currentTime = currentTime
})
local handle = Roact.mount(clockElement, PlayerGui, "Clock UI")
while true do
wait(1)
currentTime = currentTime + 1
handle = Roact.update(handle, Roact.createElement(Clock, {
currentTime = currentTime
}))
end
A stateful component manages its own currentTime in state, using lifecycle methods to start and stop an internal timer. No external Roact.update calls are needed.local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
local Roact = require(ReplicatedStorage.Roact)
local Clock = Roact.Component:extend("Clock")
function Clock:init()
self:setState({
currentTime = 0
})
end
function Clock:render()
local currentTime = self.state.currentTime
return Roact.createElement("ScreenGui", {}, {
TimeLabel = Roact.createElement("TextLabel", {
Size = UDim2.new(1, 0, 1, 0),
Text = "Time Elapsed: " .. currentTime
})
})
end
function Clock:didMount()
self.running = true
spawn(function()
while self.running do
self:setState(function(state)
return {
currentTime = state.currentTime + 1
}
end)
wait(1)
end
end)
end
function Clock:willUnmount()
self.running = false
end
local PlayerGui = Players.LocalPlayer.PlayerGui
local handle = Roact.mount(Roact.createElement(Clock), PlayerGui, "Clock UI")
wait(10)
Roact.unmount(handle)
The stateful approach is generally preferred for components that own their own data. The function component approach shines for pure, data-driven display components that receive everything they need from above.
Continue to State & Lifecycle to learn how to use setState and lifecycle methods in depth.