From fe9f4871f3eff5ce5d8e63d5782482808d03ae8e Mon Sep 17 00:00:00 2001 From: Rohan Chakraborty Date: Thu, 9 Apr 2026 11:56:52 +0530 Subject: [PATCH 1/4] wip: migration doc --- docs/V1-migration.md | 698 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 698 insertions(+) create mode 100644 docs/V1-migration.md diff --git a/docs/V1-migration.md b/docs/V1-migration.md new file mode 100644 index 000000000..056513fe2 --- /dev/null +++ b/docs/V1-migration.md @@ -0,0 +1,698 @@ +# Apsara v1.0.0 Migration Guide: Radix UI / Ariakit -> Base UI + +This guide covers all breaking changes when upgrading from the last stable Radix-based release to the current Base UI-based v1.0.0 + +--- + +## Table of Contents + +- [Prerequisites](#prerequisites) +- [Cross-Cutting Changes](#cross-cutting-changes) +- [Component Migration](#component-migration) + - [Accordion](#accordion) + - [Avatar](#avatar) + - [Breadcrumb](#breadcrumb) + - [Button](#button) + - [Checkbox](#checkbox) + - [Combobox](#combobox) + - [Data Table](#data-table) + - [Dialog](#dialog) + - [DropdownMenu -> Menu](#dropdownmenu---menu) + - [Flex](#flex) + - [Grid](#grid) + - [Popover](#popover) + - [Radio](#radio) + - [ScrollArea](#scrollarea) + - [Select](#select) + - [Separator](#separator) + - [Sheet -> Drawer](#sheet---drawer) + - [Sidebar](#sidebar) + - [Slider](#slider) + - [Switch](#switch) + - [Tabs](#tabs) + - [Toast](#toast) + - [Tooltip](#tooltip) +- [New Components](#new-components) +- [Removed Exports](#removed-exports) +- [Migration Checklist](#migration-checklist) + +--- + +## Prerequisites + +- **React 19 required.** The peer dependency changed from `^18 || ^19` to `^19` only. React 18 is no longer supported. +- The library no longer uses `radix-ui`, `@ariakit/react`, or `sonner`. It now uses `@base-ui/react` and `@base-ui/utils` internally. These are installed automatically as dependencies of the package. +- `@radix-ui/react-icons` is still used. + +--- + +## Cross-Cutting Changes + +These patterns apply across many components. Address them globally before tackling individual components. + +### `asChild` Replaced by `render` + +Radix's `asChild` composition pattern is gone. Use the `render` prop instead: + +```tsx +// Before + + +// After + +``` + +Affected components: Button, Grid, Grid.Item, Popover.Trigger, Menu.Trigger, Drawer.Trigger, and others. + +### Callback Signatures + +Most `onValueChange`, `onOpenChange`, and `onCheckedChange` callbacks now receive a second `eventDetails` argument: + +```tsx +// Before +onOpenChange={(open: boolean) => { ... }} + +// After +onOpenChange={(open: boolean, eventDetails) => { ... }} +``` + +Existing handlers that ignore extra args still work at runtime, but TypeScript types may require updating. + +### Data Attributes + +If you target Apsara component data attributes in custom CSS, these have changed globally: + +| Old (Radix) | New (Base UI) | +|-------------|---------------| +| `data-state="open"` | `data-open` | +| `data-state="closed"` | `data-closed` | +| `data-state="checked"` | `data-checked` | +| `data-state="unchecked"` | `data-unchecked` | +| `data-active-item="true"` | `data-highlighted` | +| `data-disabled="true"` | `data-disabled` (no value) | + +### CSS Variables + +If you reference these CSS variables in custom styles: + +| Old | New | +|-----|-----| +| `--radix-popover-trigger-width` | `--anchor-width` | +| `--radix-select-trigger-width` | `--anchor-width` | +| `--radix-accordion-content-height` | `--accordion-panel-height` | +| `--radix-collapsible-content-*` | Removed | + +--- + +## Component Migration + +### Accordion + +1. **`type` prop replaced with `multiple` boolean**, `collapsible` prop removed (always collapsible): + ```tsx + // Before + + + + // After + {/* single, always collapsible */} + {/* multiple mode */} + ``` + +2. **`onValueChange` in single mode** now receives `string | undefined` (not just `string`). + +3. **Type exports removed** -- `AccordionItemProps`, `AccordionTriggerProps`, `AccordionContentProps` are no longer exported. + +--- + +### Avatar + +1. **`asChild` prop removed.** +2. **`delayMs` and other Radix-specific root props** no longer recognized. + +Unchanged: `size`, `radius`, `variant`, `color`, `fallback`, `src`, `alt`, `className`, `AvatarGroup` with `max`, and `getAvatarColor`. + +--- + +### Breadcrumb + +1. **`as` prop renamed to `render`** on `BreadcrumbItem`: + ```tsx + // Before + }>... + + // After + }>... + ``` + +2. **`current` items now render `` instead of ``.** + +3. **`dropdownItems` shape changed** -- `label` -> `children`: + ```tsx + // Before + dropdownItems={[{ label: 'Option', onClick: handler }]} + + // After + dropdownItems={[{ children: 'Option', onClick: handler }]} + ``` + +--- + +### Button + +1. **`asChild` removed** -- use `render` prop: + ```tsx + // Before + + + // After + + ``` + +--- + +### Checkbox + +1. **Indeterminate API changed** -- `checked="indeterminate"` replaced by separate `indeterminate` boolean: + ```tsx + // Before + + + // After + + ``` + +2. **`onCheckedChange` now receives 2 args** -- `(checked: boolean, eventDetails)`. The `CheckedState` type (`boolean | 'indeterminate'`) no longer exists. + +3. **`CheckboxProps` type export removed.** + +#### New: `Checkbox.Group` + +```tsx + + + + +``` + +--- + +### Combobox + +1. **`onOpenChange` signature changed** -- now `(open, eventDetails)` (2 args). `onValueChange` and `onInputValueChange` are unchanged (1 arg). + +2. **Content props removed** -- `align`, `onOpenAutoFocus`, `onInteractOutside`, `onFocusOutside` no longer accepted. New: `initialFocus`, `finalFocus`. + +3. **`modal` prop removed** -- always modal. + +4. **`defaultInputValue` prop removed** -- use controlled `inputValue`. + +5. **`focusOnHover` prop removed from Item.** + +6. **Backspace-to-remove-last-chip removed** in multiple mode. + +#### New Features + +- `Combobox.useFilter` and `Combobox.useFilteredItems` hooks for declarative filtering +- Generic value type support: `>` +- `items` prop on Root for built-in filtering +- `render` prop on Content and Item + +```tsx +// Before + {}}> + + + Apple + + + +// After + {}}> + + + Apple + + +``` + +--- + +### Data Table + +- `defaultSort` is now effectively required for "Reset to default" and empty/zero state detection to work properly. +- New `totalRowCount` prop -- when provided in `mode='server'`, shows a "N items hidden by filters" message. + +--- + +### Dialog + +1. **`DialogContent` props rewritten:** + - Removed: `ariaLabel`, `ariaDescription`, `overlayBlur`, `overlayClassName`, `overlayStyle`, `scrollableOverlay` + - New: `showCloseButton` (default `true`), `overlay` (object with `blur?: boolean`, `className`, `style`), `showNestedAnimation` + +2. **CloseButton is now auto-rendered** inside Content. Remove manual `` from headers. Pass `showCloseButton={false}` to suppress. + +```tsx +// Before + + + Settings + + + + +// After + + + Settings + {/* CloseButton auto-rendered by Content */} + + +``` + +#### New Features + +- `Dialog.createHandle` for imperative open/close +- `showNestedAnimation` for stacked dialog animations +- Header/Footer/Body accept all Flex props + +--- + +### DropdownMenu -> Menu + +**Export renamed: `DropdownMenu` -> `Menu`** + +1. **Import changed:** + ```tsx + // Before + import { DropdownMenu } from '@raystack/apsara'; + + // After + import { Menu } from '@raystack/apsara'; + ``` + +2. **Nested menu API restructured** -- `TriggerItem` replaced by dedicated sub-components: + ```tsx + // Before + + Sub Menu + + Nested + + + + // After + + Sub Menu + + Nested + + + ``` + +3. **`asChild` -> `render`** on Trigger. + +4. **Search prop renames:** + - `searchValue` -> `inputValue` + - `onSearch` -> `onInputValueChange` + - `defaultSearchValue` -> `defaultInputValue` + +5. **`focusLoop` -> `loopFocus`** (default changed from `true` to `false`). + +6. **Content props:** `gutter` -> `sideOffset`. `portal`, `portalElement`, `unmountOnHide` removed. + +#### New Features + +- `Menu.Submenu`, `Menu.SubmenuTrigger`, `Menu.SubmenuContent` +- `Menu.createHandle` for imperative control +- Menubar integration + +--- + +### Flex + +- New `render` prop to change the underlying element (e.g., `render={
}`). +- Type changed to `useRender.ComponentProps<'div'>` -- may cause TypeScript errors if you typed Flex props explicitly. + +--- + +### Grid + +- `asChild` removed from both `Grid` and `Grid.Item`. Use `render`: + ```tsx + // Before +
...
+ + // After + }>... + ``` + +--- + +### Popover + +1. **`asChild` removed from Trigger** -- use `render` prop or pass children directly. +2. **`ariaLabel` custom prop removed** -- use standard `aria-label` instead. + +Positioning props (`side`, `align`, `sideOffset`, `collisionPadding`) are preserved. + +#### New Features + +- `Popover.createHandle` for imperative control +- `initialFocus` / `finalFocus` for focus management + +--- + +### Radio + +**Component hierarchy inverted** -- this is the most disruptive change: + +```tsx +// Before +import { Radio, RadioItem } from '@raystack/apsara'; + + + + + + +// After +import { Radio } from '@raystack/apsara'; + + + + + +``` + +- `RadioItem` export removed -- use `Radio` for individual items. +- `onValueChange` now receives 2 args. +- `RadioItemProps` type export removed. + +--- + +### ScrollArea + +1. **`type="auto"` removed.** Remaining options: `'always'`, `'hover'`, `'scroll'`. +2. **Default `type` changed** from `'auto'` to `'hover'`. +3. **`ScrollAreaRootProps` renamed** to `ScrollAreaProps`. + +--- + +### Select + +1. **Sub-component renames:** + - `Select.ScrollUpButton` -> `Select.ScrollUpArrow` + - `Select.ScrollDownButton` -> `Select.ScrollDownArrow` + - `Select.Viewport` -> removed (no longer needed) + +2. **`SelectContent` props removed** -- `position`, `asChild`, `onEscapeKeyDown`, `onPointerDownOutside`. + +3. **`SelectItem` uses `render` prop** instead of `asChild`. + +#### New Features + +- `items` prop for external filtering +- Explicit `disabled`, `required`, `name` props on Root + +```tsx +// Before + + +// After + +``` + +--- + +### Separator + +1. **`decorative` prop removed.** +2. **Default `aria-label` removed** -- no longer auto-generates `"horizontal separator"`. Add explicitly if needed. + +--- + +### Sheet -> Drawer + +**Export renamed: `Sheet` -> `Drawer`** + +1. **All sub-components renamed** -- `Sheet.*` -> `Drawer.*`. + +2. **`asChild` -> `render`** on Trigger. + +3. **`side` must be passed to both Root AND Content:** + ```tsx + // Before + ... + + // After + ... + ``` + +4. **Close button prop renamed** -- `close` -> `showCloseButton` (default changed to `true`). + +#### New Features + +- Swipe-to-dismiss +- Structured layout: `Drawer.Header`, `Drawer.Body`, `Drawer.Footer` +- `Drawer.createHandle` for drag handle + +```tsx +// Before + + + + Title + {content} + + + +// After + + }>Open + + + Title + + {content} + + +``` + +--- + +### Sidebar + +1. **`disabled` prop replaced by `collapsible={false}`.** + +2. **`asChild` removed from Root** -- always renders `