Two different bets
Radix UI has quietly become the accessibility backbone of the modern React ecosystem. Its Primitives are unstyled, behaviour-only building blocks — dialogs, dropdown menus, popovers, tooltips, accordions — that handle the genuinely hard parts: focus trapping, keyboard navigation, ARIA wiring, controlled and uncontrolled state, portalling and collision-aware positioning. They render close to bare DOM and ship no opinions about how anything looks, which is exactly why so many libraries (shadcn/ui among them) are built on top of them.
Radix also offers a second tier, Radix Themes, which layers a configurable, pre-styled component set over those primitives with an accent/gray/radius/scaling theming model. So the project actually spans two standpoints: raw primitives where you own every pixel of the visual layer, and Themes where you accept Radix's design language for speed. Most teams reach for the Primitives and supply the CSS themselves.
Vireya isn't really a like-for-like competitor to Radix — it sits a layer above it. Vireya consumes Radix (alongside base-ui) for accessible behaviour, then adds the part Radix Primitives deliberately leave undone: finished, styled components driven by a `--v-*` design-token system, plus pre-composed blocks and a charts library that share that same token vocabulary. In other words, the accessibility you'd get from wiring up Radix yourself is already inside Vireya's components.
The honest framing is one of layers, not rivalry. If you want primitives to style from scratch into a bespoke design system, Radix is the foundation to reach for — and you may well end up using it directly. If you want the styling, theming and composition already done on top of those same kinds of primitives, Vireya hands you that finished surface. Vireya is early (v0.1.0) and far less widely adopted than Radix, so this is a comparison of where each sits in the stack, not of maturity.
Under the hood
Layers: unstyled primitives vs styled components on top of them
Radix Primitives give you behaviour and structure with no styling — each component renders semantic, accessible DOM and exposes data attributes (`data-state`, `data-side`, and so on) plus an `asChild` slot pattern so you attach your own classes and elements. The styling is entirely yours to author, in whatever CSS technology you prefer.
Vireya occupies the layer directly above that. It builds its components on Radix and base-ui primitives for the accessible behaviour, then ships the CSS for you as static CSS Modules wired to `--v-*` tokens. You're not choosing between Radix and Vireya so much as choosing whether you author the visual layer over primitives yourself or take Vireya's finished one.
Theming: bring-your-own CSS (or Themes presets) vs a token engine
With Radix Primitives there is no theme to configure — styling lives entirely in your own CSS. Radix Themes adds a provider with a fixed set of knobs (accent color, gray scale, radius, scaling), which is fast but constrains you to that system's design decisions.
Vireya themes through `createTheme()`: a tier-based palette with light/dark and runtime switching, where one token layer drives components, blocks and charts together. You re-theme by changing token values once rather than restyling primitives or staying inside a preset's accent/gray dials.
Scope: primitives only vs components + blocks + charts
Radix is deliberately narrow — accessible interaction primitives (and, in Themes, the components built from them). Data visualisation, page-level compositions and dashboards are out of scope and assembled from other libraries.
Vireya bundles pre-composed blocks and a tokenized charts library next to the components, all sharing one token vocabulary, so a landing page, an app shell and a chart stay visually coherent without stitching separate projects together. Radix has neither blocks nor charts.
Reaching mobile: web-only vs hybrid delivery
Radix Primitives render to the DOM — they're a web concern by design, and Radix Themes is the same. Reaching iOS and Android means a separate React Native effort with different primitives entirely; nothing about Radix follows you to a native target.
Vireya layers a hybrid delivery model on top of those same kinds of primitives. You build the UI once as a web app and run it inside a native WebView shell, with a typed RPC bridge (`@vireya/rpc`) wiring native functions — payments, sensors, push — while screens render from the web. It's the Mobile Bridge pattern Shopify documented and that commerce apps like Mercado Livre and Magazine Luiza ship at scale, so the styled, accessible UI you build on Radix-grade behaviour can reach mobile without a React Native rewrite. The bridge is still maturing (Expo first via `@vireya/platform-expo`), so it's the model Vireya is designed around rather than a finished feature.
Side by side
| Vireya | Radix UI | |
|---|---|---|
| What you get | Styled, themed components + blocks + charts | Unstyled primitives (Themes adds a styled set) |
| Layer | Sits on top of primitives, ships finished UI | The primitive layer itself |
| Styling | CSS Modules + --v-* tokens, no runtime CSS | Bring your own (Primitives); Themes ships CSS |
| Theming | Token engine, tier-based palette, light/dark | None (Primitives); accent/gray/radius/scaling (Themes) |
| Charts & blocks | Bundled, same tokens | None |
| Native mobile | Hybrid: web UI in a native WebView + typed bridge | Web / DOM only |
| Accessibility | Built on Radix + base-ui | Best-in-class primitives (Vireya builds on these) |
| Maturity | Early (v0.1.0), actively built | Mature, very widely adopted |
Where Radix UI shines
- The de-facto standard for headless accessibility — rigorous, battle-tested focus management, keyboard support and ARIA wiring that countless production apps depend on daily.
- A two-tier model that fits both extremes: unstyled Primitives for total visual control, or Radix Themes for a styled set you can ship quickly.
- Per-component packaging and a lean, behaviour-only footprint, so you bundle exactly the primitives you use and nothing more.
- Enormous, well-understood adoption — it underpins shadcn/ui and many other systems, so patterns, examples and answers are everywhere.
What Vireya does differently
- Vireya ships the finished, styled component that Radix Primitives leave to you — the CSS, states and visual polish are already authored on top of the same kind of accessible behaviour.
- Theming is a single `--v-*` token engine with tier-based palettes, light/dark and runtime switching, rather than bring-your-own CSS or the fixed accent/gray/radius dials of Radix Themes.
- A charts library and pre-composed blocks come bundled and speak the components' tokens; Radix offers neither, so you'd wire those up separately.
- Vireya is built for hybrid delivery — the same web UI ships as a native mobile app through a WebView shell and a typed bridge — whereas Radix is web/DOM only.
When to choose Radix UI
- You want full control of the visual layer and are happy to author the CSS for every primitive yourself.
- You're building a bespoke design system from the ground up and want behaviour-only foundations to style your way.
- You only need the accessible interaction logic — focus, keyboard, positioning — not finished, opinionated components.
- You want the most widely adopted, battle-tested primitives in the React ecosystem today.
When to choose Vireya
- You want finished, themed components instead of unstyled primitives you have to dress yourself.
- You want a token engine, charts and blocks out of the box rather than primitives plus a pile of your own CSS.
- You need one consistent token vocabulary across components, blocks and charts, with light/dark and runtime switching.
- You want a path to ship the same UI to mobile as a hybrid native + WebView app, and would rather inherit Radix-grade accessibility than wire it up by hand.
Switching from Radix UI to Vireya
If you're hand-styling Radix Primitives today, moving to Vireya is mostly about deleting CSS rather than rewriting logic. Because Vireya builds on Radix (plus base-ui), the component mental model carries straight over — dialogs, dropdowns, popovers, tooltips and accordions behave the way you already expect, with the same kind of controlled/uncontrolled state and accessible focus handling.
The change is that the styling you previously authored per primitive becomes Vireya's tokenized CSS Modules: you map your palette, spacing and radius onto `--v-*` tokens once via `createTheme()` instead of maintaining stylesheets for every primitive. Teams migrating from Radix Themes trade its accent/gray/radius presets for the broader token engine. Both can coexist during a transition, so you can swap surface by surface and drop your custom primitive styling as Vireya equivalents land.
The bottom line
Radix UI and Vireya live at different layers of the same stack, which is why Vireya uses Radix rather than competing with it. If you want behaviour-only primitives to style into your own design system — or you're already deep in Radix and happy authoring CSS — Radix is the proven, ubiquitous foundation. If you'd rather receive finished, accessible components with the styling already done, theme everything from one token layer, get blocks and charts in the bargain, and have a path to ship that same UI to mobile as a hybrid native + WebView app, Vireya is the layer above worth adopting, provided you're comfortable with a younger project.
Still deciding? Read why teams choose Vireya, see how theming works, or browse the live blocks and charts showcases. You can also see other comparisons, browse UI library alternatives and the best library by use case, or read about Radix UI directly.
Frequently asked questions
Is Vireya an alternative to Radix UI?
It depends on what you want. Radix gives you unstyled, accessible primitives to style yourself; Vireya gives you finished, styled components — and it builds on Radix (plus base-ui) underneath. If you want to ship styled components without authoring the visual layer, Vireya is the alternative; if you want raw primitives for a bespoke design system, use Radix directly.
Does Vireya use Radix?
Yes. Vireya builds its components on Radix and base-ui primitives for accessible behaviour, focus management and keyboard handling, then adds styling via --v-* tokens plus pre-composed blocks and a charts library. The accessibility you'd get from wiring up Radix yourself is already inside Vireya's components.
Do I still have to write CSS with Vireya like I do with Radix Primitives?
No. Radix Primitives are unstyled, so you author the CSS for every component. Vireya ships static CSS Modules driven by --v-* tokens — you re-theme by changing token values via createTheme(), not by writing component styles from scratch.
How is Vireya different from Radix Themes?
Radix Themes is a styled component set on top of Radix Primitives, configured through accent, gray, radius and scaling presets. Vireya is also styled, but it themes through a broader --v-* token engine with tier-based palettes and runtime switching, and it adds blocks, charts and a hybrid mobile delivery path (web UI in a native WebView with a typed bridge) that Radix Themes does not cover.
Can Vireya reach mobile where Radix can't?
Radix renders to the DOM and is web-only. Vireya layers a hybrid delivery model on top of the same kind of primitives: the web UI runs inside a native WebView shell with a typed bridge (@vireya/rpc) for native functions — the Mobile Bridge pattern Shopify documented and apps like Mercado Livre and Magazine Luiza use — so the styled, accessible UI you build can ship to mobile without a React Native rewrite. The bridge is maturing, Expo first.
Which should I choose?
Choose Radix if you want behaviour-only primitives to style into your own design system, or you want the most widely adopted accessibility foundation today. Choose Vireya if you want finished, themed components built on those same kinds of primitives, with one token layer driving components, blocks and charts, and a path to ship the same UI as a hybrid mobile app.