# Releases

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

Source: https://docs.astra-void.xyz/lattice-ui/reference/releases/

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](https://docs.astra-void.xyz/lattice-ui/reference/migration.md), and the full entry-by-entry history in the repository's [CHANGELOG.md](https://github.com/astra-void/lattice-ui/blob/main/CHANGELOG.md).

> **Pre-1.0 versioning**
>
> 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](https://docs.astra-void.xyz/lattice-ui/getting-started/package-stability.md) 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.** `Slot` decides which child to clone by looking each element's type up in a table of UI modifiers, and that table held one spelling of each class at a time. Which spelling an element carries depends on who renders it: `@rbxts/react`'s `createElement` rewrites a host tag to its Roblox class name before building the element, so `<uicorner />` arrives as `"UICorner"`, while a browser React renderer leaves the tag as written. Keyed by tag, `asChild` failed on every styled subtree in Roblox; re-keyed by class name in 0.8.0, it failed the same way anywhere the library runs under browser React — which is what broke the `asChild` previews on this site. Both spellings are now listed.
- **`UIShadow` counts as a modifier.** It is a creatable `UIComponent` that a Tailwind-style transform emits for `shadow-*`, and it was absent under either spelling, so it failed `asChild` exactly like a casing miss.
- **Re-parented modifiers no longer collide keys with the element's own children.** Both child walks numbered from `.0`, and React may resolve a duplicate key by dropping a child rather than by warning. Reachable from any modifier sibling on an element that has children of its own.

> **If you are on 0.8.0 in Roblox, this changes nothing you can see**
>
> The 0.8.0 keying is correct for `@rbxts/react`, so a game shipped against it
>   was never affected by the first fix. The second and third are real anywhere:
>   a `shadow-*` class on an `asChild` part failed, and a modifier next to an
>   element with its own children fed React a duplicate key.

## 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](https://docs.astra-void.xyz/lattice-ui/reference/migration.md#07x--080). 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.

> **Why a `CanvasGroup` was the wrong default**
>
> A `CanvasGroup` composites its whole subtree into one offscreen layer so `GroupTransparency` can fade it as a unit. That is exactly 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.Content` accepts `asChild` — it was the last content part without it. Pass a `canvasgroup` and it becomes the motion host, so `createCanvasGroupRevealRecipe()` fades the surface as one layer again, opt-in rather than paid for by every dialog. The outside-press boundary moves down to that element's first host child, which is the same panel a plain dialog renders directly under `Content`. See [Dialog](https://docs.astra-void.xyz/lattice-ui/components/dialog.md).
- `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 the JSX tag, but `@rbxts/react` rewrites a host tag to its Roblox class name before building the element — `<uicorner />` reaches `Slot` as `"UICorner"` — so every modifier missed the lookup, counted as a second target candidate, and `asChild` failed with "expected exactly one child element besides any UI modifiers". Any component recipe that emits a `UIListLayout` or a `UICorner` hit this on every use. Re-keying it fixed Roblox and broke browser React, where the tag survives as written; 0.8.1 lists both spellings. See [styling with Vela](https://docs.astra-void.xyz/lattice-ui/guides/styling-with-vela.md) and [`asChild` composition](https://docs.astra-void.xyz/lattice-ui/guides/as-child-composition.md).

## 0.7.0

The release before it, and the largest breaking one so far. It strips every primitive down to behavior and rebuilds the CLI around the same idea.

**Migration** — see [Migration](https://docs.astra-void.xyz/lattice-ui/reference/migration.md) for the full walkthrough. In short:

- Every primitive renders unstyled. Pass the appearance you want directly to the part — 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`.

> **This release mostly does not fail to compile**
>
> It renders differently. Surfaces that looked finished on 0.6 come up flat on
>   0.7, 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 — progress fill ratios, slider thumb travel, popper position, scroll thumb size — stays owned by the primitive.
- 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](https://docs.astra-void.xyz/lattice-ui/reference/cli.md).

**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](https://docs.astra-void.xyz/vela-rbxts/index.md) emits. See [styling with Vela](https://docs.astra-void.xyz/lattice-ui/guides/styling-with-vela.md).
- `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 behavior — 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`. 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 now 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, and `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 instead of being resolved from the latest dist-tag, and `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 instead of one framework holding the unprefixed names. No runtime behavior, 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: `Select` trigger/item, toggle-group item, and accordion trigger register focus nodes and route activation through a shared guard, so 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, stays visible while its exit animation completes before removal, starts the expiry timer when it enters the visible window (not at enqueue), and animates `clear()` 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, dismiss on sunk input, and 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`).
- 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).

## Related

- [Migration](https://docs.astra-void.xyz/lattice-ui/reference/migration.md)
- [Package stability](https://docs.astra-void.xyz/lattice-ui/getting-started/package-stability.md)
- [CLI](https://docs.astra-void.xyz/lattice-ui/reference/cli.md)
- [Installation](https://docs.astra-void.xyz/lattice-ui/getting-started/installation.md)
