Comparison

Vireya vs Headless UI

A small set of completely unstyled, accessible components from Tailwind Labs, designed to pair with Tailwind CSS.

Two different bets

Headless UI comes from Tailwind Labs, the team behind Tailwind CSS, and it exists to fill a specific gap: when you style everything with Tailwind utilities, you still need a handful of interactive components that are genuinely accessible. So Headless UI ships a small, focused set — menus, dialogs, comboboxes, listboxes, popovers, tabs, switches, disclosures — that handle keyboard navigation, focus management and ARIA wiring while rendering essentially no styling of their own.

The defining trait is how it hands you control. Components expose their internal state through render props and `data-*` attributes (`data-open`, `data-active`, `data-disabled`, and so on), so you attach Tailwind classes — often via the `data-[open]:` style variants — to describe exactly how each state should look. There is no theme and no default appearance; the library owns behaviour, and you own every pixel, almost always with Tailwind.

Vireya sits a layer up from that. Rather than unstyled behaviour you dress with utility classes, it ships finished, styled components built on Radix and base-ui primitives, themed through a `--v-*` token engine, and it bundles pre-composed blocks and a charts library that share those tokens. Where Headless UI gives you accessible logic to style, Vireya gives you the styling already done — and it's built to ship that same web UI to mobile as a hybrid native + WebView app, not just to the browser.

The two aren't really like-for-like. Headless UI is a deliberately tiny behaviour layer assuming a Tailwind workflow; Vireya is a fuller, opinionated system you theme through tokens with no Tailwind requirement. Vireya is early (v0.1.0) and Headless UI is mature within its narrow scope, so the honest comparison is about how much of the visual layer you want to own, not about feature counts.

Under the hood

Standpoint: unstyled behaviour to style vs finished styled components

Headless UI ships interaction logic with no appearance. Each component surfaces its state through render props and data attributes, and you supply all visual rules — overwhelmingly as Tailwind utility classes keyed off those states. Nothing renders 'nicely' out of the box; that's by design, because it's meant to disappear into your Tailwind-driven design.

Vireya instead ships the finished component. It builds on Radix and base-ui primitives for accessible behaviour, then provides the styling for you as static CSS Modules wired to tokens. You aren't writing per-state classes for each component — the visual layer is already authored and themeable.

Styling model: Tailwind utilities and data-attributes vs tokenized CSS Modules

Because Headless UI is built by Tailwind Labs, its ergonomics assume Tailwind: you describe states with `data-[open]:`-style variants and utility classes, and your design lives in those class strings. There is no theming system — re-skinning means editing utilities wherever you used the components.

Vireya has no Tailwind dependency and no runtime CSS-in-JS. Styling is static CSS Modules whose every value is a `--v-*` token, themed through `createTheme()` with tier-based palettes, light/dark and runtime switching. You re-theme by changing token values once, and components, blocks and charts all follow.

Scope: a focused behaviour set vs components + blocks + charts

Headless UI is intentionally small — roughly a dozen-and-a-half interactive components covering the common form and overlay needs. Anything beyond that, including layout, data visualisation and page-level composition, you build yourself.

Vireya provides a fuller component set and adds pre-composed blocks and a tokenized charts library alongside it, all sharing one token vocabulary. A form, an app shell and a chart stay visually coherent without assembling separate libraries.

Reaching mobile: web-only vs hybrid delivery

Headless UI renders to the DOM and assumes a Tailwind-on-the-web workflow; there's no native target in its scope. Reaching iOS and Android is a separate React Native project with its own components, and the Tailwind classes you wrote per state don't come along.

Vireya is built around hybrid delivery. 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 the native functions you need — 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 use to ship at scale, so you reach mobile without rebuilding in React Native. The bridge is still maturing (Expo first via `@vireya/platform-expo`), so it's the model Vireya is designed for rather than a turnkey feature today.

Side by side

 VireyaHeadless UI
What you getStyled, themed components + blocks + chartsUnstyled accessible components
StylingCSS Modules + --v-* tokens, no TailwindBring your own (designed for Tailwind)
ThemingToken engine, tier-based palette, light/darkNone (you own styling)
ScopeFull component set + blocks + charts~16 focused interactive components
Charts & blocksBundled, same tokensNone
Native mobileHybrid: web UI in a native WebView + typed bridgeWeb / DOM only
AccessibilityBuilt on Radix + base-uiSolid, on its focused component set
MaturityEarly (v0.1.0), actively builtMature within a narrow scope

Where Headless UI shines

What Vireya does differently

When to choose Headless UI

When to choose Vireya

Switching from Headless UI to Vireya

If you're hand-styling Headless UI with Tailwind today, Vireya gives you finished components built on the same kind of accessible primitives, so the interaction model — menus, dialogs, comboboxes, tabs — carries over while the styling work largely disappears. The accessible behaviour you relied on Headless UI for is already inside Vireya's components via Radix and base-ui.

The real shift is leaving the Tailwind-utility-per-state workflow behind: instead of describing every `data-[open]:` and `data-active:` state in class strings, you map your palette, spacing and radius onto `--v-*` tokens once with `createTheme()` and let the components inherit them. Because Vireya has no Tailwind dependency, you can keep Tailwind in the rest of the app during a transition and replace Headless UI components surface by surface as Vireya equivalents land.

The bottom line

Headless UI and Vireya answer different questions. Headless UI asks 'how do I get accessible interactive components without giving up my Tailwind-driven design?' and answers it with a tiny, unstyled behaviour layer — and if you live in Tailwind and only need a few interactive pieces, it's hard to beat. Vireya asks 'how do I get finished, themed components plus blocks and charts that all share one token vocabulary?' and answers with a styled system you theme through `--v-*` tokens, no Tailwind required, that's built to ship the same UI to mobile as a hybrid native + WebView app. Pick Headless UI to own the styling; pick Vireya to have it done — accepting a younger project in exchange.

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 Headless UI directly.

Frequently asked questions

Is Vireya a Headless UI alternative?

For teams who want finished, styled components rather than unstyled behaviour, yes. Headless UI gives you accessible interaction logic to style with Tailwind; Vireya gives you themed components, blocks and charts via a --v-* token engine, built on Radix and base-ui, with no Tailwind requirement.

Does Vireya require Tailwind like Headless UI assumes?

No. Headless UI is designed to be styled with Tailwind utility classes keyed off its data attributes. Vireya ships static CSS Modules driven by --v-* tokens and has no Tailwind dependency, so you can use it with or without Tailwind elsewhere in the app.

Does Vireya cover more than Headless UI?

Yes. Headless UI is a deliberately small set of roughly sixteen interactive components. Vireya provides a fuller component set plus pre-composed blocks and a tokenized charts library, all sharing one --v-* token vocabulary.

Is Vireya as accessible as Headless UI?

Headless UI has solid, well-tested accessibility on the components it covers. Vireya builds on Radix and base-ui primitives, which provide rigorous focus management, keyboard handling and ARIA wiring, so accessible behaviour is built in across a broader component set.

Can Vireya ship a mobile app where Headless UI can't?

Headless UI is web/DOM only — mobile means a separate React Native build. Vireya is built for hybrid delivery: the same 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 you reach mobile without a rewrite. The bridge is maturing, Expo first.

Which should I choose?

Choose Headless UI if you're all-in on Tailwind, want to own every pixel, and only need a handful of accessible interactive components. Choose Vireya if you want finished, themed components plus blocks and charts under one token layer, no Tailwind dependency, and a path to ship the same UI as a hybrid mobile app.

More Vireya comparisons