Upgrading
Breaking changes in each Apsara release, and the steps to move your app.
One section per release, newest first, with only the changes that need action from you. The full record of every release — features and fixes included — is on GitHub releases.
1.6 — lucide replaces the radix icons
Apsara used to draw its icons with @radix-ui/react-icons.
Since 1.6 it draws them with lucide, behind stable keys
you can replace one at a time.
Some icons look different, lucide-react is a new peer dependency, and the
names @raystack/apsara/icons exports have changed.
1. Install the peer dependency
1npm install lucide-react
The range is wide — >=0.500.0 <1.0.0 — so your app picks the version. If a
lucide release changes a drawing you care about, replace that one icon (step 5)
rather than pinning the whole library.
2. Rename what you imported from @raystack/apsara/icons
That path used to export raw in-house SVG components. It now exports the 31 icons Apsara's components draw, as replaceable icon components. Twelve of the old names are gone.
| Removed name | Use instead | Appearance |
|---|---|---|
BellIcon | lucide Bell | Same glyph |
BellSlashIcon | lucide BellOff | Similar |
BuildingsFilledIcon | lucide Building2 | Solid becomes stroke |
CheckCircleFilledIcon | lucide CircleCheck | Solid becomes stroke |
CoinIcon | lucide Coins | Similar |
CoinColoredIcon | lucide Coins | Loses its color |
CrossCircleFilledIcon | lucide CircleX | Solid becomes stroke |
OrganizationIcon | lucide Building2 | Similar |
ResetIcon | lucide RotateCcw | Similar |
ShoppingBagFilledIcon | lucide ShoppingBag | Solid becomes stroke |
SidebarIcon | PanelLeftIcon, or lucide PanelLeft | Similar |
TriangleRightIcon | ChevronRightIcon | Solid triangle becomes a chevron |
Two names survive, both with a new drawing:
CoPilotIcon— lucideSparklesin place of the in-house solid sparkle.FilterIcon— lucideListFilterin place of the in-house solid funnel.
A raw lucide component draws 24×24 at strokeWidth={2}, so set
size={16} strokeWidth={1.5} at the call site to match the Apsara icons beside
it — or wrap it once with createIcon, which applies those for you:
1// src/icons.ts2import { createIcon } from '@raystack/apsara/icons';3import { Bell } from 'lucide-react';45export const BellIcon = createIcon('BellIcon', Bell);
3. Check the icons that changed shape
These are inside Apsara's own components, so they change without you touching a call site. Everything else is the same glyph in a different drawing style.
| Where | Before (radix) | After | What changed |
|---|---|---|---|
Sidebar collapse | ViewVerticalIcon | PanelLeftIcon | A different glyph |
Sidebar group toggle | TriangleDownIcon | ChevronDownIcon | A solid triangle becomes a chevron |
Menu and ContextMenu submenu marker | in-house TriangleRightIcon | ChevronRightIcon | A solid triangle becomes a chevron |
ChatPanel expand | SizeIcon | ExpandIcon | A different glyph |
ChatPanel minimize | MinusIcon | ShrinkIcon | A dash becomes the matched pair of ExpandIcon |
PromptInput stop | StopIcon | StopIcon (lucide Square) | Solid becomes stroke |
DataTable sort ascending | TextAlignTopIcon | SortAscendingIcon | A different glyph |
DataTable and DataView sort descending | TextAlignBottomIcon | SortDescendingIcon | A different glyph |
DataTable and DataView display settings | MixerHorizontalIcon | DisplayIcon | Similar |
DataTable and DataView filters | in-house FilterIcon | FilterIcon (lucide ListFilter) | A solid funnel becomes filter lines |
ChatPanel minimized bubble | in-house CoPilotIcon | CoPilotIcon (lucide Sparkles) | A solid sparkle pair becomes a stroked sparkle |
Two more are worth a look, though the glyph is nearly the same:
DatePickerandRangePickerdrawCalendarIcon, which is lucideCalendarDays, so the glyph has day marks inside it.Search's clear button andToast's error status drawCircleXin place of radixCrossCircledIcon.
4. Expect a 1px size change in some places
Every Apsara icon renders at 16×16 with strokeWidth={1.5}, which draws the
1px stroke of the design because lucide's viewBox is 24 units wide. The radix
icons were intrinsically 15×15.
- A call site that set no size grows from 15px to 16px.
- A call site that set a CSS class is unaffected — CSS beats an SVG presentation attribute.
- A call site that set
width/heightexplicitly is unaffected — your props are applied after Apsara's base values.
To change the size or the stroke of every icon at once, use the props half of
<Theme icons>:
1<Theme icons={{ props: { width: 20, height: 20, strokeWidth: 1.25 } }}>
5. If you want the radix appearance back
Apsara ships no radix preset, so register the radix icons yourself at <Theme>.
Keep @radix-ui/react-icons in your own dependencies and copy this map:
1'use client';23import {4 ArrowDownIcon,5 ArrowUpIcon,6 CalendarIcon,7 CheckCircledIcon,8 CheckIcon,9 ChevronDownIcon,10 ChevronLeftIcon,11 ChevronRightIcon,12 CopyIcon,13 Cross1Icon,14 CrossCircledIcon,15 DotsHorizontalIcon,16 ExclamationTriangleIcon,17 FileTextIcon,18 InfoCircledIcon,19 MagnifyingGlassIcon,20 MinusIcon,21 MixerHorizontalIcon,22 MoonIcon,23 PlusIcon,24 SizeIcon,25 StopIcon,26 SunIcon,27 TableIcon,28 TextAlignBottomIcon,29 TextAlignTopIcon30} from '@radix-ui/react-icons';31import { Theme, type IconOverrides } from '@raystack/apsara';3233const radixIcons: IconOverrides = {34 ArrowDownIcon: ArrowDownIcon,35 ArrowUpIcon: ArrowUpIcon,36 CalendarIcon: CalendarIcon,37 CheckIcon: CheckIcon,38 ChevronDownIcon: ChevronDownIcon,39 ChevronLeftIcon: ChevronLeftIcon,40 ChevronRightIcon: ChevronRightIcon,41 ClearIcon: CrossCircledIcon,42 CopyIcon: CopyIcon,43 DisplayIcon: MixerHorizontalIcon,44 EllipsisIcon: DotsHorizontalIcon,45 ErrorIcon: CrossCircledIcon,46 ExpandIcon: SizeIcon,47 FileTextIcon: FileTextIcon,48 InfoIcon: InfoCircledIcon,49 MinusIcon: MinusIcon,50 MoonIcon: MoonIcon,51 PlusIcon: PlusIcon,52 SearchIcon: MagnifyingGlassIcon,53 ShrinkIcon: MinusIcon,54 SortAscendingIcon: TextAlignTopIcon,55 SortDescendingIcon: TextAlignBottomIcon,56 StopIcon: StopIcon,57 SuccessIcon: CheckCircledIcon,58 SunIcon: SunIcon,59 TableIcon: TableIcon,60 WarningIcon: ExclamationTriangleIcon,61 XIcon: Cross1Icon62};6364export function Providers({ children }: { children: React.ReactNode }) {65 return <Theme icons={{ components: radixIcons }}>{children}</Theme>;66}
Three keys are not in the map, because radix has no equivalent: FilterIcon,
PanelLeftIcon and CoPilotIcon. All three were in-house SVGs before. Radix
MagicWandIcon is the nearest stand-in for CoPilotIcon if you want one.
You do not have to take the whole map. A partial map changes only the keys it names.
6. Register from a client component
An override map is an object of functions, and a function cannot cross the
boundary from a React Server Component to a Client Component. If your <Theme>
sits directly in a server layout today, move it into a providers.tsx file
marked 'use client', as shown above.
This applies to any runtime icon override.
See Icons for the full set, the override API, and what each key draws.
1.0 — Base UI replaces Radix and Ariakit
Apsara 1.0 rebuilds every component on Base UI in place of Radix UI, Ariakit, sonner and cmdk. It is the largest migration Apsara has had, and it has a dedicated guide: the v1 migration guide walks through every component with before-and-after examples. The headlines:
- React 19 is required. The peer range narrows from
^18 || ^19to^19. asChildbecomesrender. The Radix composition pattern is gone across every trigger and primitive; children move onto the wrapper.- Callbacks gain a second argument.
onValueChange,onOpenChangeandonCheckedChangenow receive aneventDetailsobject after the value. - Data attributes and CSS variables change.
data-state="open"becomesdata-open, and the--radix-*variables become Base UI names such as--anchor-width. Custom CSS that targets Apsara internals needs updating. - Form controls compose with
Field.InputFieldbecomesInput, and labels, descriptions and errors move to the newFieldwrapper. - Components are renamed.
DropdownMenubecomesMenuandSheetbecomesDrawer, each with prop renames of its own. - The pickers change contract.
DatePickerandRangePickergainslotProps, start unselected instead of defaulting to today, and require a realDate(orundefined) asvalue. - Layout scales go numeric.
FlexandGridtakegap={1}throughgap={17}in place of the named sizes, andHeadlinesizes becomet1–t4.
If you are coming from 0.x, work through the full guide in order — the cross-cutting changes first, then your components one by one.