Skip to content

Headless select / combobox comparison

How @rozie-ui/listbox compares to the existing headless select & combobox libraries across the six frameworks. Unlike Rozie's engine-wrapper components (Embla, Flatpickr, Chart.js…), the listbox has no vanilla-JS engine behind it — there is no shared "select core" the way Embla is a shared carousel core. Instead, every framework ecosystem reimplements the WAI-ARIA listbox / combobox pattern from scratch, in its own idiom. The result is the most fragmented landscape of any component Rozie ships: the best options are React-only, the one cross-framework incumbent (Headless UI) covers just React + Vue, Svelte and Solid each have their own separate community libraries, Angular gives you low-level CDK primitives you assemble yourself, and web components have no headless combobox at all. Rozie authors the ARIA behaviour once and ships it to all six.

Research snapshot: 2026-06-16. The headless-UI landscape moves quickly; treat the library names, framework coverage, and "combobox?" column as of that date.

The libraries at a glance

FrameworkRepresentative headless option(s)ShapeListboxComboboxNotes
ReactHeadless UI, Radix UI, Ariakit, React Aria, downshiftrender-props / hooks✅ (most)Deepest ecosystem by far. React Aria is the accessibility gold standard; Radix has no combobox primitive; each library is a different API.
VueHeadless UI (Vue), Reka UI, Ark UIcomponentsHeadless UI ships an official Vue port; Reka UI / Ark UI add more. Solid coverage, fewer choices than React.
SvelteMelt UI, Bits UIbuilders / actionsA separate community ecosystem — no Headless UI port. Healthy, but a different mental model (builders) again.
SolidKobalte, Ark UI (Solid), CorvucomponentsCommunity libraries; no first-party headless suite.
AngularAngular CDK (@angular/cdk/listbox)directives / primitives⚠️ primitive⚠️ experimentalCDK gives you a low-level listbox primitive — you assemble the popup, filtering, and combobox wiring yourself. The CDK combobox is experimental. Material's mat-select/mat-autocomplete are styled, not headless.
Lit / web components(none headless)No headless select/combobox primitive. Shoelace <sl-select> / Spectrum are styled components, not headless behaviour you can re-skin. You hand-roll the ARIA.
Rozie@rozie-ui/listbox-*a componentOne source → all six, same props / events / two-way value / slots / handle. Listbox and combobox in one component (a combobox boolean flip).

These libraries are excellent — on its home framework each is the obvious pick, and Rozie does not claim to out-feature React Aria on React or Melt UI on Svelte. The wedge is consistency and coverage: the cross-framework incumbent (Headless UI) stops at React + Vue; the deepest options (Radix, Ariakit, React Aria, downshift) are React-only; Svelte and Solid are separate ecosystems with separate APIs; Angular hands you primitives, not an assembled combobox; and Lit / web components have nothing headless. A team shipping a cross-framework design system today maintains a render-prop component on React, a builder on Svelte, a CDK assembly on Angular, and a hand-rolled web component for Lit — four mental models and two gaps for the same ARIA pattern. Rozie gives all six the same idiomatic <Listbox> from one definition.

Feature matrix

Cell legend: = documented out-of-the-box · = not supported / not present · ⚠️ = partial / consumer-assembly-required.

CapabilityReact (HUI/Radix/Aria…)Vue (HUI/Reka)Svelte (Melt/Bits)Solid (Kobalte)Angular (CDK)Lit (none)@rozie-ui/listbox
Headless ARIA listbox⚠️ primitive
Combobox (type-to-filter)✅ (✗ Radix)⚠️ experimental✅ (combobox flag)
Idiomatic component surface⚠️ render-props/hooks⚠️ builders⚠️ directiveshand-roll<Listbox>
Single and multi select⚠️multiple
Two-way value binding⚠️ value+onChangev-model⚠️ bind store⚠️ signal⚠️ wire CVAr-model:value (Angular CVA)
Type-ahead (printable keys)⚠️
Client filter + remote hook⚠️filterable + search event
Scoped option rendering✅ render-prop✅ slot✅ snippet⚠️ templateoption / selected / empty slots
Windowing for long lists✅ (wire a virtualizer)⚠️⚠️⚠️⚠️✅ opt-in virtual (virtual-core, ×6)
Imperative handle⚠️ varies⚠️ varies⚠️ varies⚠️ varies⚠️hand-roll✅ uniform 5-verb $expose
Zero-config styling, re-skinnable⚠️ unstyled, wire it⚠️⚠️⚠️⚠️✅ CSS-var tokens + shadcn/Material/Bootstrap bridges
One source → all 6 frameworks

Where Rozie wins today

  • One definition, six idiomatic packages — including Lit / web components, which have no headless select/combobox to begin with, and Angular, which gets a fully-assembled combobox instead of the CDK's lower-level primitives. Both are categories the incumbents simply don't serve.
  • The same component surface everywhere. Where the ecosystem offers render-props (React), components (Vue/Solid), builders (Svelte), and directives (Angular) — four mental models — @rozie-ui/listbox is one <Listbox> with the same props, events, two-way value, slots, and handle on all six.
  • Listbox and combobox in one component. combobox is a single boolean: off → an ARIA select-only button trigger; on → a role="combobox" text input that filters as you type. Several ecosystems split these into separate primitives, and Radix has no combobox at all.
  • A real two-way value on all sixr-model:value reads and writes the selection with no onChange → setState glue. Because value is the sole model: true prop, the Angular output additionally implements ControlValueAccessor, so a Listbox is a form control ([formControl] / [(ngModel)] bind directly).
  • Single + multi select, type-ahead, and a remote-filter hook out of the box — flip multiple, get array values; flip filterable="false" and listen to search to drive server-side filtering — identical on every target.
  • Zero-config styling that re-skins to any design system. Every rendered value is a --rozie-listbox-* CSS custom property with a built-in fallback, plus ready-made token bridges for shadcn/ui, Material 3, and Bootstrap 5. Most headless libraries are unstyled-and-you-wire-every-element; Rozie works on drop-in yet stays fully re-skinnable.

What Rozie defers

This page concedes where the incumbents are genuinely ahead — that's what keeps the comparison credible, and it doubles as Rozie's own roadmap.

  • React Aria's accessibility depth. React Aria is the gold standard: locale-aware type-ahead collation, RTL, exhaustive touch / pointer / virtual-cursor handling, and screen-reader testing across a large browser × AT matrix. @rozie-ui/listbox implements the APG patterns faithfully and is gate-verified across all six targets, but it does not match the breadth of React Aria's edge-case coverage. On React specifically, React Aria is the right call when that depth is the priority.
  • It's a single component, not a primitive suite. Headless UI, Radix, Ariakit, Kobalte, and Melt ship whole families — Menu, Dialog, Tabs, Popover, Tooltip, and more. Rozie ships listbox/combobox (alongside its other @rozie-ui components), not a unified headless-primitive system.
  • Deep virtualization edge cases. React Aria and others integrate full-featured list virtualizers (variable heights, sticky sections, horizontal scroll). @rozie-ui/listbox ships opt-in vertical windowing for long lists via :virtual (the same @tanstack/virtual-core engine the @rozie-ui/data-table family uses, wired in cross-framework) — only the visible slice renders, backed by behavioral specs across all six targets — but it does not yet cover the more exotic virtualization modes.
  • Batteries-included async combobox. downshift and React Aria have mature async/remote-data patterns (loading states, debounce, cancellation). Rozie gives you the search event and filterable="false" hook; the loading/debounce/cancellation policy is yours to wire.
  • @rozie-ui/listbox is 0.1.0. The surface (13 props / 3 events / single + multi / combobox / 5-verb handle / 3 slots) is stable and gate-verified across all six targets, but it is younger and less battle-tested than the established libraries.

Try it

The @rozie-ui/listbox showcase + API reference documents the @rozie-ui/listbox-* packages — one pre-compiled, per-framework install (npm i @rozie-ui/listbox-react, etc.). There is no engine to import and no required CSS — the ARIA behaviour and a fully-tokenised skin ship inside the component, with optional one-line theme bridges for shadcn/ui, Material 3, and Bootstrap 5. The live demo runs the real Vue package in the page.

Cross-references

Pre-v1.0 — internal monorepo.