Migrating to Base UI
rapidUI moved from Radix to Base UI. What changes when an app re-installs its components.
Components are copied into your app, so nothing changes until you re-install them with the shadcn CLI. Re-install a component together with the components it depends on, then work through the changes below. The looks, sizes and tokens are the same as before.
Everywhere: asChild becomes render
Base UI has no asChild. Pass the element to render with the render prop instead. A Button that renders a link also needs nativeButton={false}.
// Before
<DialogTrigger asChild>
<Button variant="outline">Edit</Button>
</DialogTrigger>
<Button asChild>
<a href="/cases">Cases</a>
</Button>
// After
<DialogTrigger render={<Button variant="outline" />}>Edit</DialogTrigger>
<Button render={<a href="/cases" />} nativeButton={false}>
Cases
</Button>This applies to every trigger and close button, and to Badge, BreadcrumbLink, Item, SidebarMenuButton, SidebarMenuAction, SidebarGroupLabel, SidebarGroupAction, SidebarMenuSubButton and the other components that used to take asChild.
Styling hooks
Base UI uses its own data attributes. Update selectors in your own classes:
data-[state=open]→data-open,data-[state=closed]→data-closeddata-[state=checked]→data-checked; tabsdata-[state=active]→data-active; togglesdata-[state=on]→data-pressed- Collapsible and accordion triggers use
data-panel-open; menu triggers usedata-popup-open - Popup size variables:
--radix-*→--anchor-width,--available-height,--transform-origin
Event handlers
Change handlers get a second eventDetails argument, for example onOpenChange(open, eventDetails) and onValueChange(value, eventDetails). Menu items use onClick instead of onSelect. Radix-only props such as forceMount, onOpenAutoFocus/onCloseAutoFocus (now initialFocus/finalFocus), onEscapeKeyDown and onInteractOutside are gone.
Component by component
Combobox and MultiSelect
Combobox is now shadcn's Combobox on Base UI, with a new API. MultiSelect is removed: use Combobox with multiple and chips.
<Combobox items={departments}>
<ComboboxInput placeholder="Select a department" showClear />
<ComboboxContent>
<ComboboxEmpty>No departments found.</ComboboxEmpty>
<ComboboxList>
{(item) => <ComboboxItem key={item} value={item}>{item}</ComboboxItem>}
</ComboboxList>
</ComboboxContent>
</Combobox>ComboboxTrigger+ComboboxValue placeholder→ComboboxInput placeholder. There is no separate search field.ComboboxItem onSelect→onValueChangeonCombobox;ComboboxGroup heading→ aComboboxLabelinside the group.loading,searchPlaceholderand the triggersizeare removed.
Select
- Pass
items(value → label) toSelect, orSelectValueshows the raw value. onValueChangereceivesvalue | null.position="popper"→alignItemWithTrigger={false}.readOnlycan be set onSelectas well as onSelectTrigger.
Menus: DropdownMenu, ContextMenu, Menubar
- A
*Labelmust be inside a*Groupor*RadioGroup, or Base UI throws. textValue→label. Checkbox and radio items stay open unless you passcloseOnClick.- Sub-menu content needs no Portal.
Dialog, AlertDialog, Sheet
Same exports. Dialogs now get a maximum height and scroll, so they work at 400% zoom. AlertDialogAction still closes the dialog.
Drawer
- Built on Base UI Drawer instead of vaul.
direction→swipeDirection(bottom→down,top→up). - The grab handle is opt-in:
showSwipeHandle. vaul-only props are gone.
Popover, Tooltip, HoverCard
PopoverAnchor→ theanchorprop onPopoverContent.PopoverTitleis anh2and names the popover.TooltipProvider delayDuration→delay; per-tooltip delays move toTooltipTrigger(delay,closeDelay).HoverCard openDelay/closeDelay→delay/closeDelayonHoverCardTrigger, which renders a link (passhref).
Accordion, Collapsible, Tabs
- Accordion:
type→multiple;collapsibleis removed (open items can always be closed);valueis an array. - Collapsible:
forceMount→keepMounted. - Tabs: arrow keys move focus and Enter or Space activates (was: activate on focus). Use
activateOnFocusonTabsListfor the old behaviour.
Checkbox, RadioGroup, Switch, Slider, ToggleGroup
- Checkbox:
checked="indeterminate"→ theindeterminateprop. - RadioGroup:
orientationis removed; all arrow keys move between options. - Slider: name it with
aria-labelledbyoraria-label(a label'shtmlForno longer works).minStepsBetweenThumbs→minStepsBetweenValues,onValueCommit→onValueCommitted. - ToggleGroup:
type→multiple;valueis always an array.
Other changes
- Separator:
decorativeis removed; passrole="none"for a purely visual line. - Progress:
classNamegoes on a wrapper; style the bar with**:data-[slot=progress-indicator]:…. Leave outvaluefor an indeterminate bar. - NavigationMenu:
viewportandNavigationMenuViewportare removed; links render ana(passhref). - ScrollArea:
typeandscrollHideDelayare removed; scrollbars show whenever the content overflows. - AspectRatio is a single element with CSS
aspect-ratio.
Dependencies
Components now depend on @base-ui/react. When no installed component uses them any more, you can remove radix-ui and vaul from your app.