Skip to main content

Roact JSX

note

The following guide assumes that you are already familiar with Roact.
Please refer to the Roact documentation for more information.

Introduction#

While roblox-ts allows you to use Roact just like you would in Luau, it also supports a "JSX" shorthand form.

import Roact from "@rbxts/roact";
const element = (
<frame Size={new UDim2(1, 0, 1, 0)}>
<frame Key="Child" Size={new UDim2(1, 0, 1, 0)} />
</frame>
);

You can learn more about JSX here.

Tag Names#

The "tag name" in JSX is the expression after the initial < character.
For example, frame is the tag name of <frame />.

You can use any Roblox UI class (host components) as a built-in JSX tag name by converting the name to lowercase.

  • Frame โ†’ frame
  • UIListLayout โ†’ uilistlayout
  • ViewportFrame โ†’ viewportframe
  • etc.

Tag names can also be custom class components or functional components.

Custom components must use PascalCase.

import Roact from "@rbxts/roact";
interface MyComponentProps {
value: string;
}
function MyComponent(props: MyComponentProps) {
return <textlabel Text={props.value} />;
}
const element = <MyComponent value="foobar" />;

Tag names can also be a property access expression to use components which are nested inside of objects or namespaces.

import Roact from "@rbxts/roact";
interface MyComponentProps {
value: string;
}
function MyComponent(props: MyComponentProps) {
return <textlabel Text={props.value} />;
}
const Components = {
MyComponent: MyComponent,
};
const element = <Components.MyComponent value="foobar" />;

Special Attributes#

Key Attribute#

The Key attribute controls what your UI Instance will be named in the DataModel. This is the same as the "Child" key in this Luau example:

Roact.createElement("Frame", {
Child = Roact.createElement("Frame", {}),
})
import Roact from "@rbxts/roact";
const element = (
<frame>
<frame Key="Child" />
</frame>
);

If an element is given the Key attribute and it not a child of another element, it will be wrapped in a Roact.Fragment.

import Roact from "@rbxts/roact";
const element = <frame Key="Child" />;

Ref Attribute#

The Ref attribute directly maps to the [Roact.Ref] key in Luau.

import Roact from "@rbxts/roact";
const ref = Roact.createRef<Frame>();
const element = <frame Ref={ref} />;

Change Attribute#

The Change attribute takes an object which maps property name -> changed function. The changed function value will be given a reference rbx to the rendered UI instance.

Note the double curly braces {{ and }}.

import Roact from "@rbxts/roact";
const element = (
<frame
Change={{
Position: (rbx) => print(`${rbx.GetFullName()} changed Position!`),
}}
/>
);

Event Attribute#

The Event attribute takes an object which maps property name -> event connection function. The event connection function value will be given a reference rbx to the rendered UI instance followed by the rest of the event arguments.

Note the double curly braces {{ and }}.

import Roact from "@rbxts/roact";
const element = (
<textbutton
Event={{
MouseButton1Down: (rbx, x, y) =>
print(`${rbx.GetFullName()} was clicked at (${x}, ${y})`),
}}
/>
);

Spreading into Attributes#

You can spread objects into attributes using the form {...exp} where exp is an object.
This is useful for creating reusable preset lists of properties.

import Roact from "@rbxts/roact";
const MyStyle: Partial<WritableInstanceProperties<Frame>> = {
BackgroundColor3: new Color3(0, 0, 0),
BackgroundTransparency: 0.5,
};
const element = <frame {...MyStyle} />;

Spreading into Children#

You can spread arrays into children using the form {...exp} where exp is a ReadonlyArray<T>.

import Roact from "@rbxts/roact";
const listItems = new Array<Roact.Element>();
for (let i = 0; i < 10; i++) {
listItems.push(<textbutton Text={`Button ${i}`} />);
}
const element = <frame>{...listItems}</frame>;

Using Values as Children#

You can use values for children using the form {exp}. This is useful for programmatically creating children. The allowed values are:

  • Roact.Element
  • ReadonlyArray<T>
  • ReadonlyMap<K, V>
  • boolean
  • undefined

boolean and undefined values do not actually get put into the children props, but allowing the values here is useful for creating conditional children values.

import Roact from "@rbxts/roact";
let condition = false;
const element = (
<frame>
{condition && <frame />}
{condition ? <frame /> : undefined}
</frame>
);

Fragments#

To create a Fragment with JSX you can either use the tag name Roact.Fragment

import Roact from "@rbxts/roact";
const fragment = <Roact.Fragment></Roact.Fragment>;

Or, you can use the shorthand form:

import Roact from "@rbxts/roact";
const fragment = <></>;