Upgrading to Base UI
How to upgrade consumer apps to the Base UI–backed registry.
This is a major version bump. The consumer-facing source API is preserved, but the underlying primitive changed
from radix-ui@1.4.x to @base-ui/react@1.4.x. Every app that consumes Redpanda UI registry components must install
the new peer dependency before re-running shadcn add.
Who this is for
Any project that installs components from the Redpanda UI Registry via
shadcn add "https://redpanda-ui-registry.netlify.app/r/<component>" or the @redpanda/... namespaced form. If you
only use the docs site or the playground, no action is needed.
One-time install
Add @base-ui/react to your dependencies and remove radix-ui if it was only pulled in transitively via the registry:
bun add @base-ui/react@^1.4.0
bun remove radix-ui # only if you don't use Radix directly elsewherenpm / pnpm / yarn work the same:
npm install @base-ui/react@^1.4.0
# or
pnpm add @base-ui/react@^1.4.0
# or
yarn add @base-ui/react@^1.4.0Re-run shadcn add
Re-install every registry component you consume so the latest source (Base UI–backed) is copied into your project:
npx shadcn@latest add "https://redpanda-ui-registry.netlify.app/r/button" \
"https://redpanda-ui-registry.netlify.app/r/dialog" \
"https://redpanda-ui-registry.netlify.app/r/popover" \
# ...and any other components you useOr, if you use the namespaced form:
npx shadcn@latest add @redpanda/button @redpanda/dialog @redpanda/popoverThe compat shim at @/lib/base-ui-compat (asChildToRender, renderWithDataState, narrowOpenChange, Slot) is
installed automatically alongside the first component that imports it — you don't need to add it explicitly.
Public API compatibility
Every public symbol is preserved byte-for-byte:
| Surface | Status |
|---|---|
| Exported component names | Unchanged |
asChild prop | Unchanged (translated to Base UI's render prop internally) |
onOpenChange(open: boolean) signature | Unchanged (compat wrapper narrows Base UI's (open, details) → (open)) |
onValueChange(value) / onCheckedChange(checked) / onPressedChange(pressed) | Unchanged |
data-state="open" | "closed" | "checked" | "unchecked" | "indeterminate" | Unchanged (compat render prop sets it alongside Base UI's native data-open / data-closed) |
data-slot="..." attributes | Unchanged |
data-orientation | Unchanged |
| Tailwind className strings | Unchanged |
If you wrote CSS against data-[state=open]:..., data-[state=checked]:..., or [data-slot="..."] — it still works.
Behavioural deviations (eight, flagged in-docs)
The compat layer could not preserve these 1:1. Each flagged component page carries a Callout with the details; the
summary:
NavigationMenuIndicator— rendered as a no-op<div>. Base UI has no indicator primitive.Menubarcontrolled-open props removed — Radix'svalue/defaultValue/onValueChangeon the root are gone. UsedefaultOpen/open/onOpenChangeon each childMenubarMenu.DropdownMenuContent.forceMount— no longer forwarded. UsekeepMountedon the Portal instead.CollapsibleContent.forceMount→keepMounted— renamed on the primitive.- Progress CSS variable —
--radix-progress-indicator-transformis gone. The indicator now writeswidthinline via Motion; rewrite any custom CSS that targeted the old var. Separator.decorative— accepted for API parity but ignored at runtime.Accordiontype="single" collapsible={false}— Base UI always allows re-close; the prop is accepted but ignored.MultiSelectContent.onOpenAutoFocus— accepted for API parity but no longer invoked. UseinitialFocuson the Popup if you need equivalent behaviour.
Full detail: MIGRATION.md.
DOM shape changes
Floating popups (Popover, Menu, Select, Tooltip, HoverCard, ContextMenu) now render an extra Positioner wrapper
between the Portal and the Popup. CSS selectors that hard-code deeply-nested element positions may need adjusting —
selectors on [role=dialog], [role=menu], [data-slot="..."], or [data-state=...] keep working.
Visual regression baselines should be re-approved after the upgrade, but no pixel-level styling of the components themselves changed.
Rollback
If the migration is blocking you, pin to the previous registry release (0.3.1) and keep radix-ui@^1.4.3. File an
issue with your Tailwind selectors, custom CSS, or consumer integration details and we will patch the compat layer.