Latticereference

Releases

Release notes and migration guidance for the lockstep-versioned @lattice-ui packages, summarized from the library changelog.

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.

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. Slot looks each child’s type up in a table of UI modifiers. That table held one spelling at a time. @rbxts/react rewrites a host tag to its Roblox class name, while a browser React renderer leaves it as written. Both are now listed.
  • UIShadow counts as a modifier, so a shadow-* class no longer fails asChild like 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.

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.Content and Toast.Root forward props onto a Frame. The CanvasGroup-only GroupTransparency and GroupColor3 no longer compile there.
  • A transition that faded a host through GroupTransparency has to animate BackgroundTransparency instead. createSurfaceRevealRecipe and createPopperEntranceRecipe are the Frame counterparts of createCanvasGroupRevealRecipe and createCanvasGroupPopperEntranceRecipe, which stay exported for a canvasgroup you slot yourself.
  • Dialog.Content is the one part with no direct replacement for a whole-surface fade, because its host spans the layer. Pass asChild with your own canvasgroup, or move the fade to the overlay dim and your own panel elements.

Highlights

  • Dialog.Content accepts asChild — the last content part without it. Pass a canvasgroup and it becomes the motion host, so createCanvasGroupRevealRecipe() fades the surface as one layer again. The outside-press boundary moves down to that element’s first host child. See Dialog.
  • createToastRevealRecipe fades BackgroundTransparency to 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

  • asChild works in Roblox on a subtree a Tailwind-style transform has styled. UI_MODIFIER_TAGS was keyed by JSX tag, so every modifier missed the lookup and counted as a second target candidate. Any recipe emitting a UIListLayout or UICorner hit it on every use. 0.8.1 finishes the job by listing both spellings. See asChild composition.

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 transition to anything that should animate. Presence timing and exit-before-unmount are unchanged.
  • Drop trackColorMode, trackOnColor, trackOffColor and disabledTrackColor from Switch.Root, and transition from RadioGroup.Item and ToggleGroup.Item.
  • Supply labels as children on Select.Item and Combobox.Item. textValue no longer renders.
  • Render the toast queue yourself inside Toast.Viewport, and supply the layout for Menu.Group and ContextMenu.Group.

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, useSelectItemContext and useComboboxItemContext, which return { highlighted, disabled } — highlighted covers hover or managed focus.
  • useFocusNode gains onFocusChange and onActivate, so a node that never becomes GuiService.SelectedObject can 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 children again. Both separators, both text inputs, the labels, descriptions and messages on TextField and Textarea, Toast.Title, Toast.Description, Select.Value, Combobox.Value, Avatar.Image and Dialog.Overlay. Attaching a UICorner or UIPadding to one of these previously did nothing.
  • asChild accepts Roblox UI modifiers as siblings of the child element, which is the shape a Tailwind-style className transform such as vela-rbxts emits. See styling with Vela.
  • Menu.Trigger no longer runs its activation twice, and Menu.Item fires onSelect exactly 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 AnchorPoint and Position rather than a declared Size.
  • lattice add context-menu and lattice add motion resolve instead of failing with “Unknown component”.
  • --dry-run reports 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-ui rather than npx lattice. npx resolves the published package name, not the shorthand alias, so npx lattice never worked on npm projects. The CLI’s own command hints now say lattice-ui, and the lattice binary 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 their react- replacements instead of leaving both names to fight over peers. doctor reports them, and upgrade skips them.

Highlights

  • create and init record the resolved package manager as a devEngines pin. add, remove and upgrade apply that pin before touching dependencies, so a project scaffolded with one manager cannot be quietly installed with another.
  • typescript is pinned to the version roblox-ts actually compiles with, rather than resolved from the latest dist-tag. doctor warns when a project is already on an unsupported major.
  • A failed install no longer leaves a half-written scaffold behind: init and create roll their file changes back.
  • The scaffolded tsconfig skips lib checks, so typecheck passes 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/core is now @lattice-ui/react-runtime — a rename of the package, not just a prefix.
  • CLI component names are mostly unchanged: lattice add dialog still works. Only the core registry key was renamed, to runtime.

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’s transition prop now takes a PresenceMotionConfig (initial/reveal/exit) instead of a ResponseMotionConfig. Update any custom toast transition to the presence shape.

Highlights

  • Overlay triggers and items are gamepad-selectable. The Select trigger 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 useActivationGuard in @lattice-ui/focus collapses the gamepad/keyboard Activated + Return/Space double-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.
  • Text gains an opt-in truncate prop that applies an end-ellipsis for single-line overflow.

Fixes

  • Dialog hosts its overlay in its own ScreenGui so 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 ScreenGui viewport 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/core to @lattice-ui/focus and @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/motion package for tween and presence helpers, and @lattice-ui/focus for focus management.
  • Placement-relative Popper positioning options (placement, sideOffset, alignOffset, collisionPadding) adopted across positioned overlays, with improved flip/clamp behavior near viewport edges.
  • usePopper exposes resolved placement/position metadata (position, anchorPoint, placement, contentSize, isPositioned, update).
  • An interactive init CLI command for existing projects, with safe template merging. create and init scaffold 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/cli with lattice-ui in 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 SwitchThumb forceMount behavior 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).
  • create CLI command for scaffolding workspace packages, with automatic npm/pnpm/yarn detection (0.4.0–0.4.2).
  • Direct ScrollArea track-click and thumb-drag interactions (0.4.0).