TSX/TypeScript → Luau compiler targeting react-lua for Roblox. Write React components in TypeScript/TSX, get clean, fully typed, dependency-free Luau that works inside Roblox.
📖 Documentation · 🛝 Playground
Unlike roblox-ts, rbx-tsx compiles to standalone Luau with no runtime dependency and preserves your TypeScript types as Luau type annotations. JSX is built in (no @rbxts/* packages or tsconfig.json JSX setup), HTML elements map to Roblox GUI classes automatically, and JS APIs (console, Math, JSON, Array, RegExp, …) are inlined directly into the output.
See the full comparison in the docs.
npm install rbx-tsx
rbx-tsx init my-app # scaffold a Rojo-ready project
cd my-app
rbx-tsx compile src/ -o out/Input (Counter.tsx):
import React, { useState, useCallback } from "react";
export default function Counter({ label }: { label: string }) {
const [count, setCount] = useState(0);
const increment = useCallback(() => setCount((c) => c + 1), []);
return (
<div className="counter">
<h1>{label}</h1>
<span>Count: {count}</span>
<button onClick={increment}>+</button>
</div>
);
}Output (Counter.luau):
const React = require(game:GetService("ReplicatedStorage").Packages.React)
const useState = React.useState
const useCallback = React.useCallback
const function Counter(props: { label: string })
const label = props.label
const count, setCount = useState(0)
const increment = useCallback(function()
setCount(function(c) return c + 1 end)
end, {})
return React.createElement("Frame", { [React.Tag] = "counter" }, {
H1 = React.createElement("TextLabel", { Text = label }),
Span = React.createElement("TextLabel", { Text = `Count: {count}` }),
Button = React.createElement("TextButton", {
[React.Event.Activated] = increment,
Text = "+",
}),
})
end
return CounterTry it live in the Playground, or browse examples/ for side-by-side input/output pairs (async/await, decorators, generators, optional chaining, regex, Roblox services, types). The demo/ directory is a full Rojo + Wally project.
rbx-tsx compile <input> # compile a file or directory (stdout or -o <path>)
rbx-tsx watch <path> # recompile on change
rbx-tsx check <input> # type-check without emitting
rbx-tsx init <name> # scaffold a new project
rbx-tsx types [path] # generate .d.ts from wally/pesde packages or local .luau modulesFull flag reference and feature details are in the docs:
- JSX & React — hooks, element & props mapping
- Language & API Transforms
- Module System & Roblox Integration
- Type System & Package Type Extraction
The docs site lives in docs-site/ (Astro Starlight) and the in-browser playground in playground/. See CLAUDE.md for the compiler architecture.