All @lattice-ui/* packages version in lockstep, so a single release number describes the whole
library. This page summarizes each release and its migration steps. The exact code changes live in
Migration, and the full entry-by-entry history in the
repository’s CHANGELOG.md.
Lattice UI is pre-1.0: minor releases (0.x) may include breaking changes,
and each release ships migration notes when they do. Read
Package stability for the
per-package stability tiers before upgrading.
0.8.1
The current stable release. A patch: three fixes to asChild’s handling of UI modifier siblings, no API change and nothing to migrate.
Fixes
- UI modifiers are recognised under both renderers.
Slotlooks each child’s type up in a table of UI modifiers. That table held one spelling at a time.@rbxts/reactrewrites a host tag to its Roblox class name, while a browser React renderer leaves it as written. Both are now listed. UIShadowcounts as a modifier, so ashadow-*class no longer failsasChildlike a casing miss.- Re-parented modifiers no longer collide keys with the element’s own children. Both child walks numbered from
.0. React may resolve a duplicate key by dropping a child rather than warning.
The 0.8.0 keying is correct for @rbxts/react, so a shipped game was never affected by the first fix. The other two are real anywhere.
0.8.0
Every motion host that used to be a CanvasGroup is now a Frame, so no primitive flattens its content into an offscreen composited layer behind your back.
Migration — see Migration. In short:
Dialog.Content,Popover.Content,Tooltip.Content,Menu.Content,ContextMenu.Content,Select.Content,Combobox.ContentandToast.Rootforward props onto aFrame. TheCanvasGroup-onlyGroupTransparencyandGroupColor3no longer compile there.- A
transitionthat faded a host throughGroupTransparencyhas to animateBackgroundTransparencyinstead.createSurfaceRevealRecipeandcreatePopperEntranceRecipeare theFramecounterparts ofcreateCanvasGroupRevealRecipeandcreateCanvasGroupPopperEntranceRecipe, which stay exported for acanvasgroupyou slot yourself. Dialog.Contentis the one part with no direct replacement for a whole-surface fade, because its host spans the layer. PassasChildwith your owncanvasgroup, or move the fade to the overlay dim and your own panel elements.
A CanvasGroup composites its whole subtree into one offscreen layer so GroupTransparency can fade it as a unit. That is right for the one effect and wrong for everything else. Children could not carry their own transparency, and every dialog, menu and tooltip paid for the layer whether or not it faded. Rendering a Frame makes the composite opt-in.
Highlights
Dialog.ContentacceptsasChild— the last content part without it. Pass acanvasgroupand it becomes the motion host, socreateCanvasGroupRevealRecipe()fades the surface as one layer again. The outside-press boundary moves down to that element’s first host child. See Dialog.createToastRevealRecipefadesBackgroundTransparencyto match its new host.- Popper measurement and placement, presence timing, exit-before-unmount, outside-dismissal boundaries, focus scoping and layer stacking are all unchanged.
Fixes
asChildworks in Roblox on a subtree a Tailwind-style transform has styled.UI_MODIFIER_TAGSwas keyed by JSX tag, so every modifier missed the lookup and counted as a second target candidate. Any recipe emitting aUIListLayoutorUICornerhit it on every use. 0.8.1 finishes the job by listing both spellings. SeeasChildcomposition.
0.7.0
The largest breaking release so far: every primitive stripped down to behavior, and the CLI rebuilt around the same idea.
Migration — see Migration for the full walkthrough. In short:
- Every primitive renders unstyled. Pass the appearance you want directly to the part, since props now forward onto the instance it renders, or use
asChild. - Motion has no defaults. Pass
transitionto anything that should animate. Presence timing and exit-before-unmount are unchanged. - Drop
trackColorMode,trackOnColor,trackOffColoranddisabledTrackColorfromSwitch.Root, andtransitionfromRadioGroup.ItemandToggleGroup.Item. - Supply labels as children on
Select.ItemandCombobox.Item.textValueno longer renders. - Render the toast queue yourself inside
Toast.Viewport, and supply the layout forMenu.GroupandContextMenu.Group.
It renders differently — surfaces that looked finished on 0.6 come up flat, because the appearance came from the primitive. Plan a visual pass, not just a typecheck.
Highlights
- Primitives now set behavior plus the minimum needed to neutralize Roblox’s own instance defaults. Geometry computed from state stays owned by the primitive: progress fill ratios, slider thumb travel, popper position, scroll thumb size.
- Unknown props forward from every part onto the instance it renders, so styling no longer requires
asChild. Consumer props override the neutral defaults but never the behavior props, consumer event handlers compose with the primitive’s rather than replacing them, and refs compose too. - Forwarded props are type-checked against that instance, so a prop the element does not accept is a compile error instead of being silently absorbed.
- Highlight state is readable through
useMenuItemContext,useContextMenuItemContext,useSelectItemContextanduseComboboxItemContext, which return{ highlighted, disabled }—highlightedcovers hover or managed focus. useFocusNodegainsonFocusChangeandonActivate, so a node that never becomesGuiService.SelectedObjectcan still render a focus highlight and take activation.activateFocusedNode()drives the same path directly.- The CLI gains per-command help pages, did-you-mean suggestions, keyboard-driven selection prompts,
NO_COLOR/FORCE_COLOR, OSC 8 hyperlinks, a working--verbose, and a single connected run of output. See the CLI reference.
Fixes
- 16 leaf parts render
childrenagain. Both separators, both text inputs, the labels, descriptions and messages onTextFieldandTextarea,Toast.Title,Toast.Description,Select.Value,Combobox.Value,Avatar.ImageandDialog.Overlay. Attaching aUICornerorUIPaddingto one of these previously did nothing. asChildaccepts Roblox UI modifiers as siblings of the child element, which is the shape a Tailwind-styleclassNametransform such as vela-rbxts emits. See styling with Vela.Menu.Triggerno longer runs its activation twice, andMenu.ItemfiresonSelectexactly once per activation.- A menu item stays highlighted while it holds keyboard focus.
- The switch thumb is centered in its track, and its travel derives from
AnchorPointandPositionrather than a declaredSize. lattice add context-menuandlattice add motionresolve instead of failing with “Unknown component”.--dry-runreports what it would do instead of claiming it ran.
0.6.2
A CLI-only patch. It changes no primitive behaviour. Every fix is about making a scaffolded project install and type-check cleanly on npm, where a peer conflict is a hard error rather than a warning.
Migration
- Use
npx lattice-uirather thannpx lattice.npxresolves the published package name, not the shorthand alias, sonpx latticenever worked on npm projects. The CLI’s own command hints now saylattice-ui, and thelatticebinary still works once the package is installed. - If your project still lists pre-0.6.1 package names, run
lattice init. It rewrites them to theirreact-replacements instead of leaving both names to fight over peers.doctorreports them, andupgradeskips them.
Highlights
createandinitrecord the resolved package manager as adevEnginespin.add,removeandupgradeapply that pin before touching dependencies, so a project scaffolded with one manager cannot be quietly installed with another.typescriptis pinned to the version roblox-ts actually compiles with, rather than resolved from the latest dist-tag.doctorwarns when a project is already on an unsupported major.- A failed install no longer leaves a half-written scaffold behind:
initandcreateroll their file changes back. - The scaffolded
tsconfigskips lib checks, sotypecheckpasses on a freshly generated project.
0.6.1
A rename-only release. Every package moved under a framework layer directory and gained a layer prefix in its published name, so future Vide and plain-Luau targets can sit beside React. No runtime behaviour, exports or APIs changed.
Migration
- Add the
react-prefix to every Lattice import:@lattice-ui/<name>is now@lattice-ui/react-<name>(for example@lattice-ui/dialog→@lattice-ui/react-dialog). @lattice-ui/coreis now@lattice-ui/react-runtime— a rename of the package, not just a prefix.- CLI component names are mostly unchanged:
lattice add dialogstill works. Only thecoreregistry key was renamed, toruntime.
Highlights
- Packages now live at
packages/<layer>/<name>and publish as@lattice-ui/<layer>-<name>, so package name and path convert 1:1. - The layer is a real directory boundary, which lets the “core must not import React” rule be enforced as a path rule.
0.6.0
The 0.6 line hardens the layered surface rather than adding new components: gamepad- and keyboard-driven selection, presence-driven overlay motion, and more reliable dismissal and positioning.
Migration
Toast.Root’stransitionprop now takes aPresenceMotionConfig(initial/reveal/exit) instead of aResponseMotionConfig. Update any custom toast transition to the presence shape.
Highlights
- Overlay triggers and items are gamepad-selectable. The
Selecttrigger and item, the toggle-group item and the accordion trigger register focus nodes and route activation through a shared guard. Gamepad users can open menus, move between items and commit without double-firing. - New
useActivationGuardin@lattice-ui/focuscollapses the gamepad/keyboardActivated+Return/Spacedouble-fire into a single activation. - Toast now runs on presence motion. It fades in on entry and stays visible while its exit animation completes. The expiry timer starts when it enters the visible window rather than at enqueue, and
clear()animates through the exit transition. Textgains an opt-intruncateprop that applies an end-ellipsis for single-line overflow.
Fixes
- Dialog hosts its overlay in its own
ScreenGuiso content renders above its dim. - Dismissable layers re-promote on open for correct z-order and dismissal order, and dismiss on sunk input. They register their trigger as an inside ref, so clicking it no longer dismisses. Outside-click dismissal also works without an explicit content boundary ref.
- Popper resolves the
ScreenGuiviewport rect from the GUI inset for more accurate placement. - Combobox keeps its selected label, and Select keeps its selected value, after content unmounts.
- Avatar re-reports loaded status for cached textures on source change. Textarea preserves its X scale during auto-resize.
0.5.1
A patch on the 0.5 line:
- Correct Combobox selection, filtering, and clear behavior.
- Declare the loom-preview example-scene dependencies so the docs previews build from a clean install.
0.5.0
Extracts shared focus and motion helpers into dedicated packages, expands CLI project scaffolding, adopts placement-relative Popper positioning, and standardizes motion behavior across layered primitives.
Migration
- Update imports that used focus or motion helpers from
@lattice-ui/coreto@lattice-ui/focusand@lattice-ui/motion. - If you regenerate projects with the CLI, review the updated pnpm hoisting and theme provider setup before shipping the scaffold.
Highlights
- New
@lattice-ui/motionpackage for tween and presence helpers, and@lattice-ui/focusfor focus management. - Placement-relative Popper positioning options (
placement,sideOffset,alignOffset,collisionPadding) adopted across positioned overlays, with improved flip/clamp behavior near viewport edges. usePopperexposes resolved placement/position metadata (position,anchorPoint,placement,contentSize,isPositioned,update).- An interactive
initCLI command for existing projects, with safe template merging.createandinitscaffold from maintained package templates. - Layered components share the same motion recipes and focus infrastructure. Overlay content stays mounted while motion is active, so exit animations complete instead of flashing or unmounting early.
- Normalized slider and switch thumb anchors so wrapped layouts keep animated thumbs aligned.
0.4.x
The 0.4 line narrowed the workspace to the maintained UI surface and introduced the shared focus manager.
Migration
- Replace
@lattice-ui/cliwithlattice-uiin install commands, scripts, and automation (0.4.3–0.4.4 renamed the published CLI package). - The preview, compiler, preview-runtime, preview-engine, and layout-engine workspace packages were dropped in 0.4.0 — depend on the maintained component packages and CLI entrypoints only.
- The deprecated
SwitchThumbforceMountbehavior and legacy roving-focus example flows were removed in 0.4.0.
Highlights
- Core focus manager primitives coordinating focus registration, ordering, and restoration across accordion, dialog, menu, popover, radio group, select, and tabs (0.4.0).
createCLI command for scaffolding workspace packages, with automatic npm/pnpm/yarn detection (0.4.0–0.4.2).- Direct
ScrollAreatrack-click and thumb-drag interactions (0.4.0).