### Basic Hello World Example
Source: https://github.com/haedrix/react-luau/blob/main/README.md
This example demonstrates how to render a simple 'Hello, [name]!' message using React Luau. It sets up a basic component and renders it to the player's GUI.
```luau
local React = require(Packages.React)
local ReactRoblox = require(Packages.ReactRoblox)
local e = React.createElement
local function HelloMessage(props: {
name: string,
})
return e("TextLabel", {
AnchorPoint = Vector2.new(0.5, 0.5),
Position = UDim2.fromScale(0.5, 0.5),
AutomaticSize = Enum.AutomaticSize.XY,
Text = `Hello, {props.name}!`,
})
end
local function App()
return e("ScreenGui", {}, {
MyMessage = e(HelloMessage, {
name = "Taylor",
}),
})
end
local root = ReactRoblox.createRoot(Instance.new("Folder"))
root:render(ReactRoblox.createPortal(e(App), Players.LocalPlayer.PlayerGui))
```
--------------------------------
### Example: Convert Specific File to Lua
Source: https://github.com/haedrix/react-luau/blob/main/docs/align-files-guide.md
An example demonstrating the file-by-file conversion command, targeting a specific utility file within the react-devtools-shared module.
```shell
dist/apps/convert-js-to-lua/index.js \
--input ../react/packages/react-devtools-shared/src/utils.js \
--output ../roact-alignment/modules/ \
--rootDir ../react/packages \
--plugin=knownImports --plugin=jestGlobals \
--babelTransformConfig babel-flow-transform-react.config.json \
--babelConfig babel-flow.config.json
```
--------------------------------
### Legacy Roact Context API Example
Source: https://github.com/haedrix/react-luau/blob/main/docs/migrating-from-1x/minimum-requirements.md
Demonstrates the legacy method of reading and defining style from context in Roact.
```lua
local AppStyle = require(script.Parent.AppStyle)
local Label = Roact.Component:extend("Label")
function Label:init()
-- reading style from context
self.style = self._context.style
end
function Label:render()
return Roact.createElement("TextLabel", {
BackgroundColor3 = self.style.LabelColor,
Text = props.text,
})
end
local App = Roact.Component:extend("App")
function App:init()
-- defining style in context
self._context.style = AppStyle
end
function App:render()
return Roact.createElement("Frame", {
Size = UDim2.fromScale(1, 1)
}, {
Start = Roact.createElement(Button, {
text = "Hello World",
})
})
end
```
--------------------------------
### Roact Class Component Constructor (init)
Source: https://github.com/haedrix/react-luau/blob/main/docs/deviations.md
This example shows the 'init' lifecycle method in Roact, which serves as the constructor for class components. It runs immediately after an instance is created and can be used for initial state setup.
```lua
local MyComponent = React.Component:extend("MyComponent")
function MyComponent:init(props)
sself.state = {
initialized = true
}
end
function MyComponent:render()
return React.createElement("TextLabel", {Text = self.props.text})
end
```
--------------------------------
### Legacy Roact Portal Example
Source: https://github.com/haedrix/react-luau/blob/main/docs/migrating-from-1x/convert-legacy-conventions.md
This snippet demonstrates how to create a modal using `Roact.Portal` in legacy Roact. The portal's target is set to `PlayerGui`.
```lua
local PlayerGui = game:GetService("Players").LocalPlayer.PlayerGui
local function Modal(props)
return Roact.createElement(Roact.Portal, {
target = PlayerGui,
}, {
Modal = Roact.createElement("ScreenGui", {}, {
Label = Roact.createElement("TextButton", {
Text = "Click me to close!",
[Roact.Event.Activated] = props.onClose,
})
})
})
end
```
--------------------------------
### Roact 17 Portal Example
Source: https://github.com/haedrix/react-luau/blob/main/docs/migrating-from-1x/convert-legacy-conventions.md
This snippet shows the equivalent modal creation in Roact 17 using `ReactRoblox.createPortal`. The target `PlayerGui` is now passed as the second argument.
```lua
local PlayerGui = game:GetService("Players").LocalPlayer.PlayerGui
local function Modal(props)
return ReactRoblox.createPortal({
Modal = Roact.createElement("ScreenGui", {}, {
Label = Roact.createElement("TextButton", {
Text = "Click me to close!",
[Roact.Event.Activated] = props.onClose,
})
})
}, PlayerGui)
end
```
--------------------------------
### React useMemo Hook Example
Source: https://github.com/haedrix/react-luau/blob/main/docs/api-reference/react.md
Shows how `useMemo` can be used to cache the result of an expensive computation. It accepts a function that computes the value and a dependency array.
```lua
local function filterByCategory(todos, category)
-- ...
return filteredTodos
end
local function FilteredTodoList(props)
local filteredTodos = React.useMemo(function()
return filterByCategory(props.todos, props.selectedCategory)
end, { props.todos, props.selectedCategory })
return React.createElement(TodoList, {
items = filteredTodos,
})
end
```
--------------------------------
### React useReducer Hook Example
Source: https://github.com/haedrix/react-luau/blob/main/docs/api-reference/react.md
Demonstrates how to use the `useReducer` hook for managing complex state logic in a component. It requires a reducer function and an initial state.
```lua
local function reducer(state, action)
if action.type == "add" then
return {
value = state.value + action.value,
ops = state.ops + 1,
}
elseif action.type == "multiply" then
return {
value = state.value * action.value,
ops = state.ops + 1,
}
end
end
local function Calculator(props)
local state, dispatch = React.useReducer(reducer, { value = 1, ops = 0 })
return React.createElement(React.Fragment, nil,
React.createElement("TextLabel", {
Text = string.format("value: %d - ops: %d", state.value, state.ops)
})
React.createElement("TextButton", {
Text = "Add 4",
[React.Event.Activated] = function()
dispatch({ type = "add", value = 4 })
end
})
React.createElement("TextButton", {
Text = "Multiply by 3",
[React.Event.Activated] = function()
dispatch({ type = "multiply", value = 3 })
end
})
)
end
```
```js
const [state, dispatch] = useReducer(reducer, initialState);
```
```lua
local state, dispatch = useReducer(reducer, initialState)
```
--------------------------------
### Roact Duplicate Key Warning Example
Source: https://github.com/haedrix/react-luau/blob/main/docs/deviations.md
This example demonstrates a scenario where Roact would issue a warning due to providing keys using both table keys and the 'key' prop simultaneously. Roact falls back to the explicitly provided key in such cases.
```lua
return React.createElement("Frame", nil, {
Label = React.createElement("TextLabel", {
key = "label1",
Text = "Hello",
})
})
```
--------------------------------
### React Component with State and Event Handling
Source: https://github.com/haedrix/react-luau/blob/main/docs/api-reference/react.md
Example of creating a React component in Luau using `Component:extend`. It demonstrates initializing state with `setState` and handling user interaction via `React.Event.Activated`.
```lua
local MyComponent = React.Component:extend("MyComponent")
function MyComponent:init()
sself:setState({ expanded = true })
end
function MyComponent:render()
return React.createElement("TextButton", {
Text = if expanded
then self.props.text
else "Click to Expand",
Size = if expanded
then UDim2.new(1, 0, 0, 200)
else UDim2.new(1, 0, 0, 30),
[React.Event.Activated] = function()
self:setState(function(expanded)
return { expanded = not expanded }
end)
end
})
end
```
--------------------------------
### Roact 17 Compatible OptionButton and ButtonGroup Components
Source: https://github.com/haedrix/react-luau/blob/main/docs/migrating-from-1x/minimum-requirements.md
This example demonstrates the fix for the reserved prop conflict by renaming the 'key' prop to 'order'. This ensures compatibility with Roact 17+.
```lua
local function OptionButton(props)
return Roact.createElement("TextButton", {
LayoutOrder = props.order,
Text = props.text,
[Roact.Event.Activated] = props.onClick,
})
end
local function ButtonGroup(props)
return Roact.createFragment({
CancelButton = Roact.createElement(OptionButton, {
order = 1,
text = "Cancel",
onClick = props.cancelCallback,
})
ConfirmButton = Roact.createElement(OptionButton, {
order = 2,
text = "Confirm",
onClick = props.confirmCallback,
})
})
end
```
--------------------------------
### Roact Component with Instance References
Source: https://github.com/haedrix/react-luau/blob/main/docs/deviations.md
This example demonstrates a basic Roact component that creates Instance references for two TextButtons. It highlights the potential issue with assigning refs directly to properties like NextSelectionRight/Left when the order of rendering is not guaranteed.
```lua
local PopupButtons = Roact.Component:extend("PopupButtons")
function PopupButtons:init()
sself.confirmRef = Roact.createRef()
sself.cancelRef = Roact.createRef()
end
function PopupButtons:render()
--[[
"Some Description"
[ Confirm ] [ Cancel ]
]]
return Roact.createElement("Frame", nil {
ConfirmButton = Roact.createElement("TextButton", {
[Roact.Ref] = self.confirmRef,
Text = "Confirm",
NextSelectionRight = self.cancelRef.value,
}),
CancelButton = Roact.createElement("TextButton", {
[Roact.Ref] = self.cancelRef,
Text = "Confirm",
NextSelectionLeft = self.confirmRef.value,
}),
})
end
```
--------------------------------
### Legacy OptionButton and ButtonGroup Components
Source: https://github.com/haedrix/react-luau/blob/main/docs/migrating-from-1x/minimum-requirements.md
This example shows a legacy implementation where 'key' is used as a prop for LayoutOrder, which conflicts with Roact's reserved 'key' prop in version 17+.
```lua
local function OptionButton(props)
return Roact.createElement("TextButton", {
LayoutOrder = props.key,
Text = props.text,
[Roact.Event.Activated] = props.onClick,
})
end
local function ButtonGroup(props)
return Roact.createFragment({
CancelButton = Roact.createElement(OptionButton, {
key = 1,
text = "Cancel",
onClick = props.cancelCallback,
})
ConfirmButton = Roact.createElement(OptionButton, {
key = 2,
text = "Confirm",
onClick = props.confirmCallback,
})
})
end
```
--------------------------------
### Creating a Binding with React.createBinding
Source: https://github.com/haedrix/react-luau/blob/main/docs/api-reference/react.md
Example of using React.createBinding to create a binding object, useful for managing state within class components. The binding can be mapped to update UI elements.
```lua
local DisplaysSize = React.Component:extend("DisplaysSize")
function DisplaysSize:init()
self.absSize, self.setAbsSize = React.createBinding(Vector2.new(0, 0))
end
function DisplaysSize:render()
return React.createElement(React.Fragment, nil,
React.createElement("ImageLabel", {
Image = self.props.image,
[React.Change.AbsoluteSize] = function(rbx)
self.setAbsSize(rbx.AbsoluteSize)
end,
}),
React.createElement("TextLabel", {
Text = self.absSize:map(function(value)
return "X = " .. tostring(value.X) .. "; Y = " .. tostring(value.Y)
end)
}
)
end
```
--------------------------------
### React useCallback Hook Example
Source: https://github.com/haedrix/react-luau/blob/main/docs/api-reference/react.md
Illustrates using `useCallback` to memoize a function, preventing unnecessary re-creations on re-renders. It takes a callback function and a dependency array.
```lua
local ItemTile = require(...)
local equipItem = require(...)
local function EquippableItemTile(props)
local onClick = React.useCallback(function()
equipItem(props.itemId)
end, { props.itemId })
return React.createElement(ItemTile, {
text = props.itemName,
onTileClicked = onClick,
})
end
```
--------------------------------
### Combine Bindings with React.joinBindings
Source: https://github.com/haedrix/react-luau/blob/main/docs/api-reference/react.md
This example demonstrates how to use React.joinBindings to combine two size bindings (aSize and bSize) into a single Size property for a Frame. The combined size is calculated by summing the individual sizes. This is useful for creating UI elements whose dimensions depend on multiple sub-elements.
```lua
local function Flex() local aSize, setASize = React.useBinding(Vector2.new()) local bSize, setBSize = React.useBinding(Vector2.new()) return React.createElement( "Frame", { Size = React.joinBindings({aSize, bSize}):map(function(sizes) local sum = Vector2.new() for _, size in sizes do sum += size end return UDim2.new(0, sum.X, 0, sum.Y) end), }, React.createElement("Frame", { Size = UDim2.new(1, 0, 0, 30), [React.Change.AbsoluteSize] = function(instance) setASize(instance.Size) end, }), React.createElement("Frame", { Size = UDim2.new(1, 0, 0, 30), Position = aSize:map(function(size) return UDim2.new(0, 0, 0, size.Y) end), [React.Change.AbsoluteSize] = function(instance) setBSize(instance.Size) end, }) ) end
```
--------------------------------
### TooltipButton Component Example
Source: https://github.com/haedrix/react-luau/blob/main/docs/migrating-from-1x/adopt-new-features.md
This Lua component demonstrates a button that shows a tooltip when clicked and hides it after a delay. It uses `React.useState` to manage the tooltip's visibility.
```lua
local function TooltipButton(props)
local showTooltip, setShowTooltip = React.useState(false)
return React.createElement("Frame", {
key = "TooltipButton",
Size = UDim2.fromScale(1, 1),
}, {
Button = React.createElement("TextButton", {
Text = "Show tooltip",
Active = props.enabled,
[React.Event.Activated] = function()
setShowTooltip(true)
task.delay(props.tooltipFadeDelay, function()
setShowTooltip(false)
end)
end,
})
Tooltip = if showTooltip
then React.createElement("TextLabel", {
Text = "Tooltip text!",
})
else nil
end)
end
```
--------------------------------
### Connecting to Roblox Events with React.Event
Source: https://github.com/haedrix/react-luau/blob/main/docs/api-reference/react.md
Example of using React.Event to connect to Roblox Instance events like MouseButton1Click. The event connection is managed automatically on mount and unmount.
```lua
Roact.createElement("ImageButton", {
[React.Event.MouseButton1Click] = function(rbx, x, y)
print(rbx, "clicked at position", x, y)
end,
})
```
--------------------------------
### Legacy ReactDOM.render Example
Source: https://github.com/haedrix/react-luau/blob/main/modules/react-roblox/README.md
This snippet shows the traditional way to render a React component into the DOM using ReactDOM.render. It is being phased out in favor of new root APIs in React 18.
```javascript
ReactDOM.render(
Hello, world!
,
document.getElementById('root')
);
```
--------------------------------
### React useRef Hook Example
Source: https://github.com/haedrix/react-luau/blob/main/docs/api-reference/react.md
Demonstrates the `useRef` hook for creating a mutable reference that persists across renders without causing re-renders. Useful for accessing DOM elements or storing non-rendering state.
```lua
local function TextBoxWithButton(props)
local textBoxRef = React.useRef(nil)
return React.createElement(React.Fragment, nil,
React.createElement("TextBox", { ref = textBoxRef }),
React.createElement("TextButton", {
Text = "->",
[React.Event.Activated] = function()
textBoxRef.current:CaptureFocus()
end
}),
)
end
```
--------------------------------
### Roact setState with Function Updater in Constructor
Source: https://github.com/haedrix/react-luau/blob/main/docs/deviations.md
This example shows using a function as the updater argument for setState within a Roact class component's 'init' method. This allows for state updates based on previous state values.
```lua
local MyComponent = React.Component:extend("MyComponent")
function MyComponent:init(props)
sself.setState(function(previousState)
return {
counter = (previousState.counter or 0) + 1
}
end)
end
function MyComponent:render()
return React.createElement("TextLabel", {Text = "Counter: " .. tostring(self.state.counter)})
end
```
--------------------------------
### Legacy Roact Mounting, Updating, and Unmounting
Source: https://github.com/haedrix/react-luau/blob/main/docs/migrating-from-1x/convert-legacy-conventions.md
Demonstrates the traditional method of managing Roact UI lifecycle using `Roact.mount`, `Roact.update`, and `Roact.unmount`.
```lua
local PlayerGui = game:GetService("Players").LocalPlayer.PlayerGui
local Roact = require(Packages.Roact)
local roactTree = Roact.mount(Roact.createElement("TextLabel", {
Text = "Hello world!",
}, PlayerGui)
task.wait(3)
roactTree = Roact.update(roactTree, Roact.createElement("TextLabel", {
Text = "Hello Roblox!",
})
task.wait(3)
Roact.unmount(roactTree)
```
--------------------------------
### Roact 17 Mounting, Updating, and Unmounting with createRoot
Source: https://github.com/haedrix/react-luau/blob/main/docs/migrating-from-1x/convert-legacy-conventions.md
Shows the Roact 17 approach using `ReactRoblox.createRoot` for managing UI lifecycle, including rendering and unmounting.
```lua
local PlayerGui = game:GetService("Players").LocalPlayer.PlayerGui
local React = require(Packages.React)
local ReactRoblox = require(Packages.ReactRoblox)
-- Roact 17 roots will take full ownership of the instance provided to them,
-- so we should not create a root using PlayerGui directly
local container = Instance.new("Folder")
container.Parent = PlayerGui
local root = ReactRoblox.createRoot(container)
root:render(Roact.createElement("TextLabel", {
Text = "Hello world!",
})
task.wait(3)
root:render(Roact.createElement("TextLabel", {
Text = "Hello Roblox!",
})
task.wait(3)
root:render(nil)
```
--------------------------------
### Legacy Ref Forwarding with Roact.Ref
Source: https://github.com/haedrix/react-luau/blob/main/docs/migrating-from-1x/minimum-requirements.md
Illustrates the legacy method of implicit ref forwarding using the `[Roact.Ref]` prop in Roact.
```lua
local function FancyButton(props)
return Roact.createElement("TextBox", {
PlaceholderText = "Enter your text here",
PlaceholderColor3 = Color3.new(0.4, 0.4, 0.4),
[Roact.Change.Text] = props.onTextChange,
-- Implicitly forwarding a ref via the `Roact.Ref` prop
[Roact.Ref] = props[Roact.Ref],
})
end
```
--------------------------------
### Require and Connect to DevTools
Source: https://github.com/haedrix/react-luau/blob/main/modules/react-devtools-core/README.md
Demonstrates how to require the React DevTools Core package and set up a connection to DevTools with a custom configuration. Ensure this is called before importing any React packages.
```luau
local ReactDevtoolsCore = require(Packages.ReactDevtoolsCore)
local connectToDevtools = ReactDevtoolsCore.connectToDevtools
connectToDevTools(config)
```
--------------------------------
### Roact 17+ Context API with createContext
Source: https://github.com/haedrix/react-luau/blob/main/docs/migrating-from-1x/minimum-requirements.md
Shows how to use Roact 17's createContext API for managing and consuming context, replacing the legacy context approach.
```lua
local AppStyle = require(script.Parent.AppStyle)
local StyleContext = Roact.createContext(nil)
local Label = Roact.Component:extend("Label")
function Label:render()
return Roact.createElement(StyleContext.Consumer, {
render = function(style)
return Roact.createElement("TextLabel", {
BackgroundColor3 = style.LabelColor,
Text = props.text,
end
})
end
})
local App = Roact.Component:extend("App")
function App:render()
return Roact.createElement(StyleContext.Provider, {
value = AppStyle,
}, {
App = Roact.createElement("Frame", {
Size = UDim2.fromScale(1, 1)
}, {
Start = Roact.createElement(Button, {
text = "Hello World",
})
})
})
end
```
--------------------------------
### Basic Ref Usage for UI Elements
Source: https://github.com/haedrix/react-luau/blob/main/modules/react-roblox/README.md
Demonstrates the basic usage of Roact refs for TextButton elements, including setting text and initial neighbor selection.
```lua
local PopupButtons = Roact.Component:extend("PopupButtons")
function PopupButtons:init()
sself.confirmRef = Roact.createRef()
sself.cancelRef = Roact.createRef()
end
function PopupButtons:render()
--[[
"Some Description"
[ Confirm ] [ Cancel ]
]]
return Roact.createElement("Frame", nil {
ConfirmButton = Roact.createElement("TextButton", {
[Roact.Ref] = self.confirmRef,
Text = "Confirm",
NextSelectionRight = self.cancelRef.value,
}),
CancelButton = Roact.createElement("TextButton", {
[Roact.Ref] = self.cancelRef,
Text = "Confirm",
NextSelectionLeft = self.confirmRef.value,
}),
})
end
```
--------------------------------
### Count React children
Source: https://github.com/haedrix/react-luau/blob/main/docs/api-reference/react.md
Use React.Children.count to get the total number of children provided to a component. This is useful for logging or conditional logic based on the number of children.
```lua
local function List(props)
print(string.format("Render list with %d children", React.Children.count(props.children)))
return React.createElement(
"Frame",
{ Size = UDim2.fromScale(1, 1) },
props.children,
)
end
```
--------------------------------
### Ref Usage with Bindings for UI Navigation
Source: https://github.com/haedrix/react-luau/blob/main/modules/react-roblox/README.md
Illustrates how using refs as bindings can solve issues with assigning neighbor selections in Roact, ensuring correct property assignment regardless of render order.
```lua
-- ...
return Roact.createElement("Frame", nil {
ConfirmButton = Roact.createElement("TextButton", {
[Roact.Ref] = self.confirmRef,
Text = "Confirm",
-- pass the ref itself, which is a binding
NextSelectionRight = self.cancelRef,
}),
CancelButton = Roact.createElement("TextButton", {
[Roact.Ref] = self.cancelRef,
Text = "Confirm",
-- pass the ref itself, which is a binding
NextSelectionLeft = self.confirmRef,
}),
})
-- ...
```
--------------------------------
### useEffect Dependency Array in React JS
Source: https://github.com/haedrix/react-luau/blob/main/docs/deviations.md
In React JS, useEffect accepts a dependency array to determine re-invocation. This example shows a typical usage where the effect re-runs only if 'count' changes.
```javascript
useEffect(() => {
document.title = `You clicked ${count} times`;
}, [count]); // Only re-run the effect if count changes
```
--------------------------------
### Create and Join Bindings
Source: https://github.com/haedrix/react-luau/blob/main/modules/react-roblox/README.md
Provides functions for creating and joining bindings, a Roact feature tightly coupled with refs.
```lua
ReactRoblox.createBinding(nil)
ReactRoblox.joinBindings(binding1, binding2)
```
--------------------------------
### Getting the Single Child with RoactCompat
Source: https://github.com/haedrix/react-luau/blob/main/docs/api-reference/roact-compat.md
RoactCompat.oneChild is a compatibility method for legacy Roact.oneChild, designed to extract a single child element from various inputs, including a table containing one element.
```Lua
RoactCompat.oneChild(
children: { [string | number]: ReactElement } | ReactElement | nil
): ReactElement
```
--------------------------------
### RoactCompat.Ref for Legacy Roact
Source: https://github.com/haedrix/react-luau/blob/main/docs/api-reference/roact-compat.md
Shows how to use Roact.Ref with legacy Roact prop tables. This field is equivalent to the string 'ref' in RoactCompat.
```lua
Roact.createElement("TextLabel", {
Text = "Hello",
[Roact.Ref] = textLabelRef,
})
```
--------------------------------
### Mapping Binding Values for Display
Source: https://github.com/haedrix/react-luau/blob/main/docs/api-reference/react.md
The map method transforms a binding's value into a new binding, suitable for display or use with Roblox Instance properties. This example formats a count into a user-friendly string.
```lua
local function UpdateOnClick()
local count, setCount = React.useBinding(0)
return React.createElement("TextButton", {
Text = count:map(function(value)
return string.format("Clicked %d times", value)
end),
[React.Event.Activated] = function()
setCount(count:getValue() + 1)
end,
})
end
```
--------------------------------
### Mounting an Element with RoactCompat
Source: https://github.com/haedrix/react-luau/blob/main/docs/api-reference/roact-compat.md
Use RoactCompat.mount to render a ReactElement into a container, mimicking legacy Roact's mounting behavior. It returns a handle for subsequent updates or unmounting.
```Lua
RoactCompat.mount(
element: ReactElement,
container: Instance?,
name: string?
): RoactTree
```
--------------------------------
### Using RoactCompat Portal
Source: https://github.com/haedrix/react-luau/blob/main/docs/api-reference/roact-compat.md
The RoactCompat.Portal component is a compatibility layer that mimics legacy Roact.Portal, using React.createPortal internally to render children into a different DOM subtree.
```Lua
RoactCompat.Portal
```
--------------------------------
### Roact useEffect with Potential Dependency Array Warning
Source: https://github.com/haedrix/react-luau/blob/main/docs/deviations.md
This Roact example illustrates a scenario where a dependency array's length might change between renders, potentially causing warnings in React JS. Roact 17+ introduces deviations to handle this.
```lua
local root = ReactRoblox.createRoot(someContainer)
local function Component(props: { A: number, B: number? })
React.useEffect(function()
-- Trigger some effect
end, { props.A, props.B })
return nil
end
-- does not warn:
root:render(React.createElement(Component, { A = 1, B = 2 }))
-- subsequent render warns about different length arrays:
root:render(React.createElement(Component, { A = 1 }))
```
--------------------------------
### React.memo for Performance Optimization
Source: https://github.com/haedrix/react-luau/blob/main/docs/api-reference/react.md
Demonstrates using `React.memo` to create a memoized component for performance optimization. This is useful when a component renders the same output given the same props.
```lua
local MyComponent = React.memo(function MyComponent(props)
--[[ render using props ]]
end)
```
--------------------------------
### RoactCompat.mount
Source: https://github.com/haedrix/react-luau/blob/main/docs/api-reference/roact-compat.md
Mounts a React element into a container, mimicking legacy Roact's mount behavior. It creates a root, renders the element, and returns a handle for updates and unmounting. It handles legacy root creation and uses Portals to avoid tampering with existing container children.
```APIDOC
## RoactCompat.mount
### Description
Compatibility method mimicking legacy `Roact.mount`. Creates a root, renders the provided element into the container, and returns an opaque handle to the root.
### Method
`RoactCompat.mount(element: ReactElement, container: Instance?, name: string?): RoactTree`
### Parameters
* **element** (ReactElement) - The React element to mount.
* **container** (Instance?, optional) - The DOM Instance to mount the element into.
* **name** (string?, optional) - An optional name for the tree.
### Returns
* **RoactTree** - An opaque handle to the root, usable with `RoactCompat.update` and `RoactCompat.unmount`.
```
--------------------------------
### Creating a Fragment with RoactCompat
Source: https://github.com/haedrix/react-luau/blob/main/docs/api-reference/roact-compat.md
RoactCompat.createFragment mimics legacy Roact's createFragment, utilizing React.Fragment internally to group multiple elements.
```Lua
RoactCompat.createFragment(elements: { [string | number]: ReactElement }): ReactElement
```
--------------------------------
### Roact 17+ Explicit Ref Forwarding with forwardRef
Source: https://github.com/haedrix/react-luau/blob/main/docs/migrating-from-1x/minimum-requirements.md
Demonstrates explicit ref forwarding in Roact 17+ using the `Roact.forwardRef` API, which is the recommended approach.
```lua
local FancyButton = Roact.forwardRef(function(props, ref)
return Roact.createElement("TextBox", {
PlaceholderText = "Enter your text here",
PlaceholderColor3 = Color3.new(0.4, 0.4, 0.4),
[Roact.Change.Text] = props.onTextChange,
-- Explicitly forwarding a ref passed in via `forwardRef`
[Roact.Ref] = ref,
end)
end)
```
--------------------------------
### Applying CollectionService Tags with React.Tag
Source: https://github.com/haedrix/react-luau/blob/main/docs/api-reference/react.md
Shows how to use React.Tag to apply CollectionService tags to a host component. Multiple tags can be applied using a space-delimited string.
```lua
local button = Roact.createElement("TextButton", {
[React.Tag] = "confirm-button"
Text = "Confirm",
-- ...
})
```
```lua
[React.Tag] = "some-tag some-other-tag"
```
--------------------------------
### RoactCompat.Children for Legacy Roact
Source: https://github.com/haedrix/react-luau/blob/main/docs/api-reference/roact-compat.md
Demonstrates forwarding children using Roact.Children with legacy Roact. This field is equivalent to the string 'children' in RoactCompat.
```lua
-- forwards the children provided to this component
Roact.createElement("Frame", nil, self.props[Roact.Children])
```
--------------------------------
### Migrate Legacy Roact Context.Consumer Usage
Source: https://github.com/haedrix/react-luau/blob/main/docs/migrating-from-1x/convert-legacy-conventions.md
Adapt legacy Roact `Context.Consumer` usage, which uses a `render` prop, to the Roact 17 pattern that expects children as a function.
```lua
local ThemeContext = Roact.createContext(nil)
-- ...
local function Button(props)
return Roact.createElement(ThemeContext.Consumer, {
render = function(theme)
return Roact.createElement("TextButton", {
BackgroundColor3 = theme.ButtonColor,
Text = props.text,
[Roact.Event.Activated] = props.onActivated,
})
end
})
end
```
```lua
local ThemeContext = Roact.createContext(nil)
-- ...
local function Button(props)
return Roact.createElement(ThemeContext.Consumer, nil,
function(theme)
return Roact.createElement("TextButton", {
BackgroundColor3 = theme.ButtonColor,
Text = props.text,
[Roact.Event.Activated] = props.onActivated,
})
end
end
```
--------------------------------
### Add Roact 17 Dependencies to New Projects
Source: https://github.com/haedrix/react-luau/blob/main/docs/migrating-from-1x/upgrading-to-roact-17.md
Add these lines to your `rotriever.toml` to include Roact 17 packages for a new project. Ensure you are using Rotriever version 0.5.4 or newer.
```toml
[dependencies]
React = "github.com/roblox/roact-alignment@17.0.1"
ReactRoblox = "github.com/roblox/roact-alignment@17.0.1"
```
--------------------------------
### Convert Entire Module to Lua
Source: https://github.com/haedrix/react-luau/blob/main/docs/align-files-guide.md
Use this command to convert all JavaScript files within a specified directory to Lua. This is suitable for smaller modules or when you want to convert a large set of files at once.
```shell
dist/apps/convert-js-to-lua/index.js \
--input ../react/packages/react-devtools-shared/src/**/*.js \
--output ../roact-alignment/modules/ \
--rootDir ../react/packages \
--plugin=knownImports --plugin=jestGlobals \
--babelTransformConfig babel-flow-transform-react.config.json \
--babelConfig babel-flow.config.json
```
--------------------------------
### RoactCompat.Portal
Source: https://github.com/haedrix/react-luau/blob/main/docs/api-reference/roact-compat.md
A compatibility component that mimics `Roact.Portal`. It internally uses the `React.createPortal` function.
```APIDOC
## RoactCompat.Portal
### Description
Compatibility component mimicking `Roact.Portal`. Uses the `React.createPortal` function under the hood.
### Component
`RoactCompat.Portal`
### Props
* **children** (ReactElement) - The children to render within the portal.
* **target** (Instance) - The target Instance where the children will be rendered.
```
--------------------------------
### Using ReactRoblox.createRoot for Concurrent Mode
Source: https://github.com/haedrix/react-luau/blob/main/docs/migrating-from-1x/adopt-new-features.md
In new code, always use ReactRoblox.createRoot to enable Concurrent Mode and improve application responsiveness. This is the recommended entry point for rendering Roact UI elements in Roact 17.
```lua
local ReactRoblox = require(ReplicatedStorage.ReactRoblox)
local root = ReactRoblox.createRoot(workspace.App)
root:render(React.createElement('ScreenGui'))
```
--------------------------------
### Testing Tooltip Behavior with `act`
Source: https://github.com/haedrix/react-luau/blob/main/docs/migrating-from-1x/adopt-new-features.md
This Lua test suite demonstrates how to use the `act` function to test component behavior, including rendering, state changes, and asynchronous operations like delayed callbacks. It ensures that all scheduled work is flushed before assertions.
```lua
local React = require(Packages.React)
local ReactRoblox = require(Packages.ReactRoblox)
local container, root
beforeEach(function()
container = Instance.new("ScreenGui")
container.Parent = Players.LocalPlayer.PlayerGui
root = ReactRoblox.createRoot(container)
end)
afterEach(function()
container:Destroy()
end)
it("shows a tooltip on click and hides it after a delay", function()
-- Use `act` for the initial render
ReactRoblox.act(function()
-- Render the button in a disabled state
root:render(React.createElement(TooltipButton, {
enabled = false,
tooltipFadeDelay = 1,
}))
end)
expect(container.TooltipButton.Tooltip).toBeNil()
expect(container.TooltipButton.Button.Active).toBe(false)
-- Use `act` to re-render the tree
ReactRoblox.act(function()
-- Rerender in the enabled state
root:render(React.createElement(TooltipButton, {
enabled = true,
tooltipFadeDelay = 1,
}))
end)
expect(container.TooltipButton.Tooltip).toBeNil()
expect(container.TooltipButton.Button.Active).toBe(true)
-- Use `act` to trigger virtual input
local element = Rhodium.Element.new(container.TooltipButton.Button)
ReactRoblox.act(function()
-- Click the button to trigger the tooltip
element:click()
Rhodium.VirtualInput.waitForInputEventsProcessed()
end)
expect(container.TooltipButton.Tooltip).never.toBeNil()
expect(container.TooltipButton.Tooltip.Text).toEqual("Tooltip text!")
-- Use `act` to resume queued renders after a delayed callback fires
ReactRoblox.act(function()
task.wait(1)
end)
expect(container.TooltipButton.Tooltip).toBeNil()
end)
```
--------------------------------
### Roact List with Table Keys
Source: https://github.com/haedrix/react-luau/blob/main/docs/deviations.md
This snippet demonstrates how to render a list of items using table keys in Roact. It iterates over a table of numbers and assigns a string representation of the index as the key for each TextLabel element.
```lua
-- Returns a fragment of items in an ordered list
function NumberList(props)
local numbers = props.numbers
for i, number in numbers do
local key = tostring(i)
listItems[key] = React.createElement("TextLabel", {
Text = key,
LayoutOrder = i,
})
end);
return listItems
end
```
--------------------------------
### Roact setState in Constructor (Recommended)
Source: https://github.com/haedrix/react-luau/blob/main/docs/deviations.md
This snippet demonstrates the recommended way to use setState within the 'init' method (constructor) of a Roact class component. It shows how to update state using setState, avoiding direct assignment to self.state.
```lua
local MyComponent = React.Component:extend("MyComponent")
function MyComponent:init(props)
sself.setState({
initialized = true
})
end
function MyComponent:render()
return React.createElement("TextLabel", {Text = self.props.text})
end
```
--------------------------------
### Setting Global Configuration with RoactCompat
Source: https://github.com/haedrix/react-luau/blob/main/docs/api-reference/roact-compat.md
RoactCompat.setGlobalConfig is a compatibility method that mimics legacy Roact.setGlobalConfig. However, it is a no-op in Roact 17 and does not apply any global configuration.
```Lua
RoactCompat.setGlobalConfig(configValues: { [string]: boolean })
```
--------------------------------
### RoactCompat.Ref for Roact 17
Source: https://github.com/haedrix/react-luau/blob/main/docs/api-reference/roact-compat.md
Shows the equivalent prop table for Roact 17, which uses 'ref' as a reserved prop name. This is compatible with RoactCompat.
```lua
Roact.createElement("TextLabel", {
Text = "Hello",
ref = textLabelRef,
})
```
--------------------------------
### React.createElement
Source: https://github.com/haedrix/react-luau/blob/main/docs/api-reference/react.md
Creates a React element. This is used directly in Luau as JSX is not supported. It takes the element type, props, and children as arguments.
```APIDOC
## React.createElement
### Description
Creates a React element. This is used directly in Luau as JSX is not supported. It takes the element type, props, and children as arguments.
### Signature
```lua
React.createElement(type, [props], [...children])
```
### Example
```lua
local element = React.createElement(
"Frame",
{ Size = UDim2.fromScale(1, 1) },
React.createElement("TextLabel", { Text = "Child1" })
React.createElement("TextLabel", { Text = "Child2" })
)
```
```
--------------------------------
### Configure Roact Dependencies in rotriever.toml
Source: https://github.com/haedrix/react-luau/blob/main/docs/migrating-from-1x/upgrading-to-roact-17.md
Declare dependencies on both legacy Roact and Roact 17 (RoactCompat) in your rotriever.toml manifest file. RoactCompat is listed as a dev dependency.
```toml
[dependencies]
Roact = "github.com/roblox/roact@1.4"
[dev_dependencies]
RoactCompat = "github.com/roblox/roact-alignment@17.0.1"
```
--------------------------------
### Roact List with 'key' Prop
Source: https://github.com/haedrix/react-luau/blob/main/docs/deviations.md
This snippet shows how to render a list of items using the special 'key' prop in Roact. It iterates over a table of numbers and assigns a string representation of the index to the 'key' prop of each TextLabel element.
```lua
-- Returns a fragment of items in an ordered list
function NumberList(props)
local numbers = props.numbers
for i, number in numbers do
local key = tostring(i)
local element = React.createElement("TextLabel", {
key = key,
Text = key,
LayoutOrder = i,
})
table.insert(listItems, element)
end);
return listItems
end
```
--------------------------------
### Updating an Element with RoactCompat
Source: https://github.com/haedrix/react-luau/blob/main/docs/api-reference/roact-compat.md
Use RoactCompat.update to re-render an existing Roact tree with a new element. The tree handle must be from a prior RoactCompat.mount or RoactCompat.update call.
```Lua
RoactCompat.update(tree: RoactTree, element: ReactElement): RoactTree
```
--------------------------------
### Connecting to Property Changes with React.Change
Source: https://github.com/haedrix/react-luau/blob/main/docs/api-reference/react.md
Demonstrates using React.Change to connect to property change signals on Roblox Instances, such as CanvasPosition for ScrollingFrame. The connection is managed automatically.
```lua
Roact.createElement("ScrollingFrame", {
[React.Change.CanvasPosition] = function(rbx)
print("ScrollingFrame scrolled to", rbx.CanvasPosition)
end,
})
```
--------------------------------
### Access Instances with React.createRef
Source: https://github.com/haedrix/react-luau/blob/main/docs/api-reference/react.md
Create a ref object using React.createRef to access underlying Roblox Instances. This is useful for direct interaction with Instances.
```lua
local MyComponent = React.Component:extend("MyComponent")
function MyComponent:init()
self.inputRef = React.createRef()
end
function MyComponent:render()
return React.createElement("TextBox", { ref = self.inputRef })
end
function MyComponent:componentDidMount()
sself.inputRef.current:CaptureFocus()
end
```
--------------------------------
### RoactCompat.Children for Roact 17
Source: https://github.com/haedrix/react-luau/blob/main/docs/api-reference/roact-compat.md
Shows the equivalent prop table for Roact 17, which uses 'children' as a reserved prop name. This is compatible with RoactCompat.
```lua
-- forwards the children provided to this component
Roact.createElement("Frame", nil, self.props.children)
```
--------------------------------
### Convert Single File to Lua
Source: https://github.com/haedrix/react-luau/blob/main/docs/align-files-guide.md
This command converts a specific JavaScript file to Lua. It's recommended for modules with many unconverted files, allowing for more granular control over the conversion process.
```shell
dist/apps/convert-js-to-lua/index.js \
--input ../react/packages/react-devtools-shared/src/ \
--output ../roact-alignment/modules/ \
--rootDir ../react/packages \
--plugin=knownImports --plugin=jestGlobals \
--babelTransformConfig babel-flow-transform-react.config.json \
--babelConfig babel-flow.config.json
```
--------------------------------
### Using useBinding Hook in a Function Component
Source: https://github.com/haedrix/react-luau/blob/main/docs/migrating-from-1x/adopt-new-features.md
Demonstrates how to use the useBinding hook to manage state in a function component. Updates to the binding directly update subscribed values without re-rendering the component.
```lua
local React = require(Packages.React)
function ClickerComponent(props)
local count, setCount = React.useBinding(0)
local function onClick()
-- This will only update subscribed host properties, specifically the
-- Text field of the button that's rendered below
setCount(count:getValue() + 1)
end
React.useEffect(function()
print(string.format("You've clicked %d times!", count))
end)
return React.createElement("TextButton", {
Text = count:map(tostring),
[React.Event.Activated] = onClick,
})
end
```
--------------------------------
### Replace Legacy Roact Dependency
Source: https://github.com/haedrix/react-luau/blob/main/docs/migrating-from-1x/upgrading-to-roact-17.md
Modify your `rotriever.toml` to use the RoactCompat package for backward compatibility with legacy Roact APIs. This allows upgrading without immediate code changes if minimum requirements are met.
```toml
[dependencies]
Roact = { target = "github.com/roblox/roact-alignment", version = "17.0.1", package = "RoactCompat" }
```
--------------------------------
### Add Roact 17 and ReactRoblox Dependencies
Source: https://github.com/haedrix/react-luau/blob/main/docs/migrating-from-1x/upgrading-to-roact-17.md
To access new Roact 17 features like hooks and suspense, add `React` and `ReactRoblox` dependencies alongside `RoactCompat` in your `rotriever.toml`.
```toml
[dependencies]
Roact = { target = "github.com/roblox/roact-alignment", version = "17.0.1", package = "RoactCompat" }
React = "github.com/roblox/roact-alignment@17.0.1"
ReactRoblox = "github.com/roblox/roact-alignment@17.0.1"
```
--------------------------------
### Create a Context Object with React.createContext
Source: https://github.com/haedrix/react-luau/blob/main/docs/api-reference/react.md
Use React.createContext to create a Context object. Context provides a way to pass data through the component tree without prop drilling.
```lua
local MyContext = React.createContext(defaultValue)
```
--------------------------------
### Convert Legacy Roact Fragment Creation
Source: https://github.com/haedrix/react-luau/blob/main/docs/migrating-from-1x/convert-legacy-conventions.md
Replace `Roact.createFragment` with `React.createElement(React.Fragment, ...)` to use fragments in Roact 17, aligning with React JS.
```lua
local function LabeledButton(props)
return Roact.createFragment({
Button = Roact.createElement("ImageButton", {
Image = props.buttonIcon,
}),
Label = Roact.createElement("TextLabel", {
Text = props.labelText,
}),
})
end
```
```lua
local function LabeledButton(props)
return React.createElement(React.Fragment, nil, {
Button = React.createElement("ImageButton", {
Image = props.buttonIcon,
}),
Label = React.createElement("TextLabel", {
Text = props.labelText,
}),
})
end
```
--------------------------------
### Creating Updatable Bindings with useBinding
Source: https://github.com/haedrix/react-luau/blob/main/docs/api-reference/react.md
useBinding creates a Binding object and an updater function, similar to useState. Bindings are isolated containers that automatically update when their value changes.
```lua
local function DisplaysSize(props)
local absSize, setAbsSize = React.useBinding(Vector2.new(0, 0))
return React.createElement(React.Fragment, nil,
React.createElement("ImageLabel", {
Image = props.image,
[React.Change.AbsoluteSize] = function(rbx)
setAbsSize(rbx.AbsoluteSize)
end,
}),
React.createElement("TextLabel", {
Text = absSize:map(function(value)
return "X = " .. tostring(value.X) .. "; Y = " .. tostring(value.Y)
end)
}
)
end
```
--------------------------------
### RoactCompat.setGlobalConfig
Source: https://github.com/haedrix/react-luau/blob/main/docs/api-reference/roact-compat.md
Mimics legacy Roact's `setGlobalConfig`. However, this function is a no-op in Roact 17 and does not apply any global configuration.
```APIDOC
## RoactCompat.setGlobalConfig
### Description
Compatibility method mimicking `Roact.setGlobalConfig`. **This does not apply to Roact 17, so calling this function is a no-op.**
### Method
`RoactCompat.setGlobalConfig(configValues: { [string]: boolean })`
### Parameters
* **configValues** ({ [string]: boolean }) - An object containing configuration values. This parameter is ignored.
```
--------------------------------
### RoactCompat.update
Source: https://github.com/haedrix/react-luau/blob/main/docs/api-reference/roact-compat.md
Updates a previously mounted React tree with a new element, mimicking legacy Roact's update behavior. This function requires a handle obtained from `RoactCompat.mount` or a previous `RoactCompat.update` call.
```APIDOC
## RoactCompat.update
### Description
Compatibility method mimicking legacy `Roact.update`. Updates a mounted tree with a new element.
### Method
`RoactCompat.update(tree: RoactTree, element: ReactElement): RoactTree`
### Parameters
* **tree** (RoactTree) - The handle returned from a prior call to `RoactCompat.mount` or `RoactCompat.update`.
* **element** (ReactElement) - The new React element to render.
### Returns
* **RoactTree** - An opaque handle to the root, usable with `RoactCompat.update` and `RoactCompat.unmount`.
```