Lattice UI is a set of headless primitives for rbxts/react. Each ships as its own
@lattice-ui/react-<name> package. It owns the tricky interaction work, such as open state, focus,
layering and motion, and leaves the visuals to you.
The rest of getting started uses Dialog as the worked example, so @lattice-ui/react-dialog is a
good place to start.
Every package is namespaced by framework layer: @lattice-ui/<name> became @lattice-ui/react-<name>, and @lattice-ui/core is now @lattice-ui/react-runtime. Upgrading from 0.6.0 or earlier, add the prefix to every import and run npx lattice-ui init to rewrite the old names in package.json. Leaving both listed makes the two copies resolve side by side, which npm rejects.
Prerequisites
Lattice UI runs on rbxts/react, so the React runtime should already be available.
import React from "@rbxts/react";import ReactRoblox from "@rbxts/react-roblox";@rbxts/react and @rbxts/react-roblox are peer dependencies of every primitive
(^17.3.7-ts.1) and are not bundled — install them yourself.
Install a package
pnpm add @lattice-ui/react-dialognpm install @lattice-ui/react-dialogyarn add @lattice-ui/react-dialogbun add @lattice-ui/react-dialogInstall one primitive at a time. Each pulls in the foundations it needs — every primitive depends on
@lattice-ui/react-runtime, and Dialog also brings react-focus, react-layer and react-motion.
import { Dialog } from "@lattice-ui/react-dialog";Use the lattice CLI
The lattice CLI installs primitives for you, adds the @rbxts/react peers, and resolves your
package manager from the project lockfile. It needs Node 20+ and runs straight from npm.
npx lattice-ui add dialogThe argument is the registry name (dialog), which the CLI maps to @lattice-ui/react-dialog. Add
several at once, space- or comma-separated, or pull in a preset: overlay bundles popover, tooltip,
dialog and toast, form bundles checkbox, radio-group, switch, text-field and textarea. See the
CLI reference.
npx lattice-ui add dialog toast --preset overlayadd with no names and no --preset prompts interactively, and --dry-run prints the exact
install command without touching anything.
It also scaffolds and maintains projects. lattice create starts a new rbxts project and
lattice init wires the toolchain into an existing one. lattice remove and lattice upgrade keep
primitives in sync, and lattice doctor checks the setup.
The manual install works with any package manager. The CLI supports pnpm, npm and yarn — pass --pm <pnpm|npm|yarn> to override what it detects from your lockfile.
Verify it works
Render the minimum useful surface to confirm the import resolves and the primitive mounts:
import React from "@rbxts/react";import { Dialog } from "@lattice-ui/react-dialog";
export function SmokeTest() { return ( <Dialog.Root defaultOpen> <Dialog.Portal> <Dialog.Content> <textlabel BackgroundTransparency={1} Size={UDim2.fromOffset(220, 40)} Text="Lattice UI is installed" /> </Dialog.Content> </Dialog.Portal> </Dialog.Root> );}Next step
Build a real, controlled surface in Your first dialog.