Why I switched to Base UI
February 24, 2026
Why I switched to Base UI
I used Radix UI for almost every project since 2023. It's excellent — accessible, composable, well-tested. But every time I needed to customize rendering, I hit the same friction: asChild.
The asChild problem
Radix's asChild prop uses Slot internally to merge props onto a child element. It works, but it creates invisible coupling between parent and child, and debugging style conflicts requires understanding the merge algorithm.
// Radix: asChild merges props onto the child
<TooltipTrigger asChild>
<button className="my-button">Hover me</button>
</TooltipTrigger>The render prop alternative
Base UI uses render props instead. You pass the element directly, and Base UI renders it with the necessary accessibility attributes:
// Base UI: render prop gives you full control
<TooltipTrigger render={<button className="my-button" />}>
Hover me
</TooltipTrigger>The difference is subtle but meaningful. With render, there's no prop merging magic. You can see exactly what element will be rendered. TypeScript can fully type-check the render target.
What I gained
- No more
asChilddebugging - Better TypeScript inference on composed elements
- Simpler mental model for customization
- Smaller bundle — Base UI ships less runtime code
What I gave up
- Radix has a larger ecosystem of pre-built components
- Some Base UI components are still experimental
- Community resources and examples are more abundant for Radix
For my use case — building custom UI from primitives — the tradeoff was worth it.