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
| Vireya | Headless UI | |
|---|---|---|
| What you get | Styled, themed components + blocks + charts | Unstyled accessible components |
| Styling | CSS Modules + --v-* tokens, no Tailwind | Bring your own (designed for Tailwind) |
| Theming | Token engine, tier-based palette, light/dark | None (you own styling) |
| Scope | Full component set + blocks + charts | ~16 focused interactive components |
| 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 | Solid, on its focused component set |
| Maturity | Early (v0.1.0), actively built | Mature within a narrow scope |
Where Headless UI shines
- A tiny, focused API that feels native alongside Tailwind, with state exposed through render props and data attributes that map cleanly onto utility variants.
- Maintained by Tailwind Labs, so it tracks Tailwind's conventions closely and integrates with that ecosystem with essentially no friction.
- Solid, well-tested accessibility — keyboard navigation, focus management and ARIA wiring — on the common form and overlay components it covers.
- An extremely light footprint: you ship only behaviour and your own classes, with no default styling weighing down the bundle.
What Vireya does differently
- Vireya hands you finished, styled components rather than unstyled behaviour you have to dress with Tailwind utilities for every state.
- Theming runs through a `--v-*` token engine with light/dark and runtime switching, and there's no Tailwind dependency to carry along.
- A charts library and pre-composed blocks ship in the box and share the components' tokens; Headless UI provides neither.
- 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 Headless UI is web/DOM only.
When to choose Headless UI
- You're already all-in on Tailwind and want to style every component yourself with utility classes.
- You only need a handful of accessible interactive components — menus, dialogs, comboboxes — and nothing broader.
- You want the lightest possible behaviour layer with zero opinion about appearance.
- Staying inside the Tailwind Labs ecosystem and conventions matters to your team.
When to choose Vireya
- You want finished, themed components instead of unstyled behaviour you style per state.
- You'd rather theme with `--v-*` tokens than maintain Tailwind utility classes across every component.
- You want a fuller component set plus blocks and a charts library that share one token vocabulary.
- You want a path to ship the same web UI to mobile as a hybrid native + WebView app, or you'd prefer no Tailwind dependency at all.
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.