Skip to content

API Reference

Methods

Roact.createElement

Roact.createElement(component, [props, [children]]) -> RoactElement

Creates a new Roact element representing the given component. Elements are lightweight descriptions about what a Roblox Instance should look like, like a blueprint!

The children argument is shorthand for adding a Roact.Children key to props. It should be specified as a dictionary of names to elements.

component can be a string, a function, or a table created by Component:extend.

Caution

Make sure not to modify props or children after they're passed into createElement!


Roact.createFragment

Added in Roact 1.0.0

Roact.createFragment(elements) -> RoactFragment

Creates a new Roact fragment with the provided table of elements. Fragments allow grouping of elements without the need for intermediate containing objects like Frames.

Caution

Make sure not to modify elements after they're passed into createFragment!


Roact.mount

Roact.mount(element, [parent, [key]]) -> RoactTree

Info

Roact.mount is also available via the deprecated alias Roact.reify. It will be removed in a future release.

Creates a Roblox Instance given a Roact element, and optionally a parent to put it in, and a key to use as the instance's Name.

The result is a RoactTree, which is an opaque handle that represents a tree of components owned by Roact. You can pass this to APIs like Roact.unmount. It'll also be used for future debugging APIs.


Roact.update

Roact.update(tree, element) -> RoactTree

Info

Roact.update is also available via the deprecated alias Roact.reconcile. It will be removed in a future release.

Updates an existing instance handle with a new element, returning a new handle. This can be used to update a UI created with Roact.mount by passing in a new element with new props.

update can be used to change the props of a component instance created with mount and is useful for putting Roact content into non-Roact applications.

As of Roact 1.0, the returned RoactTree object will always be the same value as the one passed in.


Roact.unmount

Roact.unmount(tree) -> void

Info

Roact.unmount is also available via the deprecated alias Roact.teardown. It will be removed in a future release.

Destroys the given RoactTree and all of its descendants. Does not operate on a Roblox Instance -- this must be given a handle that was returned by Roact.mount.


Roact.oneChild

Roact.oneChild(children) -> RoactElement | nil

Given a dictionary of children, returns a single child element.

If children contains more than one child, oneChild function will throw an error. This is intended to denote an error when using the component using oneChild.

If children is nil or contains no children, oneChild will return nil.


Roact.createBinding

Added in Roact 1.0.0

Roact.createBinding(initialValue) -> Binding, updateFunction
where
    updateFunction: (newValue) -> ()

The first value returned is a Binding object, which will typically be passed as a prop to a Roact host component. The second is a function that can be called with a new value to update the binding.

A Binding has the following API:

getValue

Binding:getValue() -> value

Returns the internal value of the binding. This is helpful when updating a binding relative to its current value.

Warning

Using getValue inside a component's render method is dangerous! Using the unwrapped value directly won't allow Roact to subscribe to a binding's updates. To guarantee that a bound value will update, use the binding itself for your prop value.

map

Binding:map(mappingFunction) -> Binding
where
    mappingFunction: (value) -> mappedValue

Returns a new binding that maps the existing binding's value to something else. For example, map can be used to transform an animation progress value like 0.4 into a property that can be consumed by a Roblox Instance like UDim2.new(0.4, 0, 1, 0).


Roact.joinBindings

Added in Roact 1.1.0

Roact.joinBindings(bindings) -> Binding
where
    bindings: { [any]: Binding }

Combines multiple bindings into a single binding. The new binding's value will have the same keys as the input table of bindings.

joinBindings is usually used alongside Binding:map:

local function Flex()
    local aSize, setASize = Roact.createBinding(Vector2.new())
    local bSize, setBSize = Roact.createBinding(Vector2.new())

    return Roact.createElement("Frame", {
        Size = Roact.joinBindings({aSize, bSize}):map(function(sizes)
            local sum = Vector2.new()

            for _, size in ipairs(sizes) do
                sum = sum + size
            end

            return UDim2.new(0, sum.X,  0, sum.Y)
        end),
    }, {
        A = Roact.createElement("Frame", {
            Size = UDim2.new(1, 0, 0, 30),
            [Roact.Change.AbsoluteSize] = function(instance)
                setASize(instance.Size)
            end,
        }),
        B = Roact.createElement("Frame", {
            Size = UDim2.new(1, 0, 0, 30),
            Position = aSize:map(function(size)
                return UDim2.new(0, 0, 0, size.Y)
            end),
            [Roact.Change.AbsoluteSize] = function(instance)
                setBSize(instance.Size)
            end,
        }),
    })
end

Roact.createRef

Roact.createRef() -> Ref

Creates a new reference object that can be used with Roact.Ref.


Roact.forwardRef

Added in Roact 1.4.0

Roact.forwardRef(render: (props: table, ref: Ref) -> RoactElement) -> RoactComponent

Creates a new component given a render function that accepts both props and a ref, allowing a ref to be forwarded to an underlying host component via Roact.Ref.


Roact.createContext

Added in Roact 1.3.0

Roact.createContext(defaultValue: any) -> RoactContext

type RoactContext = {
    Provider: Component,
    Consumer: Component,
    [private fields]
}

Creates a new context provider and consumer. For a usage guide, see Advanced Concepts: Context.

defaultValue is given to consumers if they have no Provider ancestors. It is up to users of Roact's context API to turn this case into an error if it is an invalid state.

Provider and Consumer are both Roact components.

Provider

Provider accepts the following props:

  • value: The value to put into the tree for this context value.
    • If the Provider is updated with a new value, any matching Consumer components will be re-rendered with the new value.
  • [Children]: Any number of children to render underneath this provider.
    • Descendants of this component can receive the provided context value by using Consumer.

Consumer

Consumer accepts just one prop:

  • render(value) -> RoactElement | nil: A function that will be invoked to render any children.
    • render will be called every time Consumer is rendered.

Roact.setGlobalConfig

Roact.setGlobalConfig(configValues: Dictionary<string, bool>) -> void

The entry point for configuring Roact. Roact currently applies this to everything using this instance of Roact, so be careful using this with a project that has multiple consumers of Roact.

Once config values are set, they will apply from then on. This is primarily useful when developing as it can enable features that validate your code more strictly. Most of the settings here incur a performance cost and should typically be disabled in production environments.

Call this method once at the root of your project (before mounting any Roact elements):

Roact.setGlobalConfig({
    typeChecks = true,
    propValidation = true,
})

The following are the valid config keys that can be used, and what they do.

typeChecks

Enables type checks for Roact's public interface. This includes some of the following:

  • Check that the props and children arguments to Roact.createElement are both tables or nil
  • Check that setState is passing self as the first argument (it should be called like self:setState(...))
  • Confirm the Roact.mount's first argument is a Roact element
  • And much more!

internalTypeChecks

Enables type checks for internal functionality of Roact. This is typically only useful when debugging Roact itself. It will run similar type checks to those mentioned above, but only the private portion of the API.

elementTracing

When enabled, Roact will capture a stack trace at the site of each element creation and hold onto it, using it to provide additional details on certain kinds of errors. If you get an error that says "", try enabling this config value to help with debugging.

Enabling elementTracing also allows the use of the getElementTraceback method on Component, which can also be helpful for debugging.

propValidation

Enables validation of props via the validateProps method on components. With this flag enabled, any validation written by component authors in a component's validateProps method will be run on every prop change. This is helpful during development for making sure components are being used correctly.


Constants

Roact.Children

This is the key that Roact uses internally to store the children that are attached to a Roact element.

If you're writing a new function component or stateful component that renders children like a host component, you can access Roact.Children in your props table.


Roact.Ref

Use Roact.Ref as a key into the props of a host element to receive a handle to the underlying Roblox Instance.

Assign this key to a ref created with createRef:

local ExampleComponent = Roact.Component:extend("ExampleComponent")

function ExampleComponent:init()
    -- Create a ref.
    self.ref = Roact.createRef()
end

function ExampleComponent:render()
    return Roact.createElement("Frame", {
        -- Use the ref to point to this rendered instance.
        [Roact.Ref] = self.ref,
    })
end

function ExampleComponent:didMount()
    -- Refs are a kind of binding, so we can access the Roblox Instance using getValue.
    print("Roblox Instance", self.ref:getValue())
end

Info

Ref objects have a deprecated field called current that is always equal to the result of getValue. Assigning to the current field is not allowed. The field will be removed in a future release.

Alternatively, you can assign it to a function instead:

Roact.createElement("Frame", {
    -- The provided function will be called whenever the rendered instance changes.
    [Roact.Ref] = function(rbx)
        print("Roblox Instance", rbx)
    end,
})

Warning

When Roact.Ref is given a function, Roact does not guarantee when this function will be run relative to the reconciliation of other props. If you try to read a Roblox property that's being set via a Roact prop, you won't know if you're reading it before or after Roact updates that prop!

Warning

When Roact.Ref is given a function, it will be called with nil when the component instance is destroyed!

See the refs guide for more details.


Roact.Event

Index into Roact.Event to receive a key that can be used to connect to events when creating host elements:

Roact.createElement("ImageButton", {
    [Roact.Event.MouseButton1Click] = function(rbx, x, y)
        print(rbx, "clicked at position", x, y)
    end,
})

Info

Event callbacks receive the Roblox Instance as the first parameter, followed by any parameters yielded by the event.

Warning

When connecting to the Changed event, be careful not to call setState or other functions that will trigger renders. This will cause Roact to re-render during a render, and errors will be thrown!

See the events guide for more details.


Roact.Change

Index into Roact.Change to receive a key that can be used to connect to GetPropertyChangedSignal events.

It's similar to Roact.Event:

Roact.createElement("ScrollingFrame", {
    [Roact.Change.CanvasPosition] = function(rbx)
        print("ScrollingFrame scrolled to", rbx.CanvasPosition)
    end,
})

Warning

Property changed events are fired by Roact during the reconciliation phase. Be careful not to accidentally trigger a re-render in the middle of a re-render, or an error will be thrown!


Roact.None

Roact.None is a special value that can be used to clear elements from your component state when calling setState or returning from getDerivedStateFromProps.

In Lua tables, removing a field from state is not possible by setting its value to nil because nil values mean the same thing as no value at all. If a field needs to be removed from state, it can be set to Roact.None when calling setState, which will ensure that the resulting state no longer contains it:

function MyComponent:didMount()
    self:setState({
        fieldToRemove = Roact.None
    })
end

Component Types

Roact.Component

The base component instance that can be extended to make stateful components.

Call Roact.Component:extend("ComponentName") to make a new stateful component with a given name.


Roact.PureComponent

An extension of Roact.Component that only re-renders if its props or state change.

PureComponent implements the shouldUpdate lifecycle event with a shallow equality comparison. It's optimized for use with immutable data structures, which makes it a perfect fit for use with frameworks like Rodux.

PureComponent is not always faster, but can often result in significant performance improvements when used correctly.


Roact.Portal

A component that represents a portal to a Roblox Instance. Portals are created using Roact.createElement.

Any children of a portal are put inside the Roblox Instance specified by the required target prop. That Roblox Instance should not be one created by Roact.

Portals are useful for creating dialogs managed by deeply-nested UI components, and enable Roact to represent and manage multiple disjoint trees at once.

See the Portals guide for a small tutorial and more details about portals.


Component API

defaultProps

static defaultProps: Dictionary<any, any>

If defaultProps is defined on a stateful component, any props that aren't specified when a component is created will be taken from there.


init

init(initialProps) -> void

init is called exactly once when a new instance of a component is created. It can be used to set up the initial state, as well as any non-render related values directly on the component.

Use setState inside of init to set up your initial component state:

function MyComponent:init()
    self:setState({
        position = 0,
        velocity = 10
    })
end

In older versions of Roact, setState was disallowed in init, and you would instead assign to state directly. It's simpler to use setState, but assigning directly to state is still acceptable inside init:

function MyComponent:init()
    self.state = {
        position = 0,
        velocity = 10
    }
end

render

render() -> Element | nil

render describes what a component should display at the current instant in time.

Info

Roact assumes that render act likes a pure function: the result of render must depend only on props and state, and it must not have side-effects.

function MyComponent:render()
    -- This is okay:
    return Roact.createElement("TextLabel", {
        Text = self.props.text,
        Position = self.state.position
    })

    -- Ack! Depending on values outside props/state is not allowed!
    return Roact.createElement("TextLabel", {
        Text = self.someText,
        Position = getMousePosition(),
    })
end

render must be defined for all components. The default implementation of render throws an error; if your component does not render anything, define a render function that returns nil explicitly. This helps make sure that you don't forget to define render!

function MyComponent:render()
    return nil
end

setState

setState(stateUpdater | stateChange) -> void

setState requests an update to the component's state. Roact may schedule this update for a later time or resolve it immediately.

If a function is passed to setState, that function will be called with the current state and props as arguments:

function MyComponent:didMount()
    self:setState(function(prevState, props)
        return {
            counter = prevState.counter + 1
        }
    end)
end

If this function returns nil, Roact will not schedule a re-render and no state will be updated.

If a table is passed to setState, the values in that table will be merged onto the existing state:

function MyComponent:didMount()
    self:setState({
        foo = "bar"
    })
end

Setting a field in the state to Roact.None will clear it from the state. This is the only way to remove a field from a component's state!

Warning

setState can be called from anywhere except:

  • Lifecycle hooks: willUnmount, willUpdate
  • Pure functions: render, shouldUpdate

Calling setState inside of init has special behavior. The result of setState will be used to determine initial state, and no additional updates will be scheduled.

Roact may support calling setState in currently-disallowed places in the future.

Warning

setState does not always resolve synchronously! Roact may batch and reschedule state updates in order to reduce the number of total renders.

When depending on the previous value of state, like when incrementing a counter, use the functional form to guarantee that all state updates occur!

This behavior will be similar to the future behavior of React 17. See:


shouldUpdate

shouldUpdate(nextProps, nextState) -> bool

shouldUpdate provides a way to override Roact's rerendering heuristics.

By default, components are re-rendered any time a parent component updates, or when state is updated via setState.

PureComponent implements shouldUpdate to only trigger a re-render any time the props are different based on shallow equality. In a future Roact update, all components may implement this check by default.


validateProps

Added in Roact 1.0.0

static validateProps(props) -> (false, message: string) | true

validateProps is an optional method that can be implemented for a component. It provides a mechanism for verifying inputs passed into the component.

Every time props are updated, validateProps will be called with the new props before proceeding to shouldUpdate or init. It should return the same parameters that assert expects: a boolean, true if the props passed validation, false if they did not, plus a message explaining why they failed. If the first return value is true, the second value is ignored.

For performance reasons, property validation is disabled by default. To use this feature, enable propValidation via setGlobalConfig:

Roact.setGlobalConfig({
    propValidation = true
})

See setGlobalConfig for more details.

Note

validateProps is a static lifecycle method. It does not have access to self, and must be a pure function.

Warning

Depending on the implementation, validateProps can impact performance. Recommended practice is to enable prop validation during development and leave it off in production environments.


getElementTraceback

getElementTraceback() -> string | nil

getElementTraceback gets the stack trace that the component was created in. This allows you to report error messages accurately.

Lifecycle Methods

In addition to the base Component API, Roact exposes additional lifecycle methods that stateful components can hook into to be notified of various steps in the rendering process.

didMount

didMount() -> void

didMount is fired after the component finishes its initial render. At this point, all associated Roblox Instances have been created, and all components have finished mounting.

didMount is a good place to start initial network communications, attach events to services, or modify the Roblox Instance hierarchy.


willUnmount

willUnmount() -> void

willUnmount is fired right before Roact begins unmounting a component instance's children.

willUnmount acts like a component's destructor, and is a good place to disconnect any manually-connected events.


willUpdate

willUpdate(nextProps, nextState) -> void

willUpdate is fired after an update is started but before a component's state and props are updated.


didUpdate

didUpdate(previousProps, previousState) -> void

didUpdate is fired after at the end of an update. At this point, Roact has updated the properties of any Roblox Instances and the component instance's props and state are up to date.

didUpdate is a good place to send network requests or dispatch Rodux actions, but make sure to compare self.props and self.state with previousProps and previousState to avoid triggering too many updates.


getDerivedStateFromProps

static getDerivedStateFromProps(nextProps, lastState) -> nextStateSlice

Used to recalculate any state that depends on being synchronized with props.

Generally, you should use didUpdate to respond to props changing. If you find yourself copying props values to state as-is, consider using props or memoization instead.

getDerivedStateFromProps should return a table that contains the part of the state that should be updated.

function MyComponent.getDerivedStateFromProps(nextProps, lastState)
    return {
        someValue = nextProps.someValue
    }
end

As with setState, you can set use the constant Roact.None to remove a field from the state.

Note

getDerivedStateFromProps is a static lifecycle method. It does not have access to self, and must be a pure function.

Caution

getDerivedStateFromProps runs before shouldUpdate and any non-nil return will cause the state table to no longer be shallow-equal. This means that a PureComponent will rerender even if nothing actually changed. Similarly, any component implementing both getDerivedStateFromProps and shouldUpdate needs to do so in a way that takes this in to account.