Skip to content

Headless slider / range comparison

How @rozie-ui/slider compares to the existing slider libraries across the six frameworks. Like the listbox, the slider has no shared vanilla-JS engine, but unlike the listbox, the cross-framework slider landscape splits along a second axis: headless-behaviour libraries (React Aria, Radix, Kobalte, Melt, Angular CDK) that reimplement the WAI-ARIA slider pattern per ecosystem, versus the native-input wrappers (rc-slider, MUI Slider, noUiSlider) that ship a styled, batteries-included widget. Rozie sits deliberately in a third spot: @rozie-ui/slider builds the behaviour on the browser's own <input type="range"> and delivers the same <Slider> on all six frameworks, with the same props, events, two-way value, slots, and handle, installed as a pre-compiled per-framework package with no Rozie toolchain required.

Research snapshot: 2026-08-10. The headless-UI landscape moves quickly; treat the library names, framework coverage, and feature columns as of that date.

The libraries at a glance

FrameworkRepresentative option(s)ShapeHeadlessRangeNative inputNotes
ReactReact Aria, Radix Slider, rc-slider, MUI Sliderhooks / components✅ (Aria/Radix)⚠️ (Aria/Radix re-implement; rc/MUI custom DOM)Deepest ecosystem. React Aria is the accessibility gold standard; Radix is headless-but-unstyled; rc-slider / MUI are styled widgets with their own custom thumbs (not native <input>).
VueReka UI Slider, Element Plus, Vuetifycomponents✅ (Reka)Reka UI ports the Radix model; Element/Vuetify are styled. Fewer headless choices than React.
SvelteMelt UI, Bits UIbuilders / actionsA separate community ecosystem (builders) — no Radix/Headless-UI port; its own mental model again.
SolidKobalte Slider, Ark UI (Solid)componentsCommunity headless libraries; no first-party suite.
AngularAngular CDK (no slider) / Material mat-slidercomponents⚠️✅ (Material 3 uses native input internally)The CDK has no headless slider primitive. mat-slider is a styled Material component, not headless behaviour you re-skin.
Lit / web components(none headless)No headless slider primitive. Shoelace (archived March 2026 in favour of Web Awesome) <sl-range> is a styled single-thumb component (no range), not re-skinnable headless behaviour. You hand-roll the ARIA.
noUiSliderframework-agnostic vanillaimperative lib⚠️The closest cross-framework option — but it owns its own DOM/drag engine, ships its own (overridable) CSS, and you write a thin wrapper per framework yourself. Not native <input>, not idiomatic-component.
Rozie@rozie-ui/slider-*a component✅ (native <input type=range>)Same API on all six: props / events / two-way value / slots / handle. Single and range in one component (a range boolean flip), built on the native input.

On its home framework each of these is a solid pick. The case for Rozie is consistency, coverage, and the native-input foundation: no headless slider spans every framework; React Aria and Radix are React-only (Reka, Kobalte, and Melt are separate ports with separate APIs); the Angular CDK has no slider; Lit / web components have nothing headless; and noUiSlider, the one agnostic option, is a vanilla engine you wrap per framework yourself. @rozie-ui/slider gives them all the same <Slider>.

Native input vs. headless: the tradeoff

The deepest design choice is what the thumb actually is. Two camps:

  • Re-implemented headless (React Aria, Radix, Kobalte, Melt, noUiSlider): a <div>-based thumb with hand-authored pointer/keyboard/ARIA handling. Maximum control over drag physics, multi-thumb layouts, and exotic interactions, at the cost of re-implementing (and re-testing) drag, touch, keyboard, focus, and ARIA in JavaScript, per library.
  • Native <input type="range"> (MUI internally, Shoelace, Rozie): the browser owns drag (mouse and touch), keyboard, focus, role="slider", aria-value*, step/min/max, disabled, and RTL. You inherit the platform's accessibility and input handling for free; the tradeoff is that styling requires the cross-browser vendor pseudo-elements (::-webkit-slider-thumb / ::-moz-range-thumb) and dual-thumb range needs the two-overlapping-inputs technique.

Rozie picks the native-input camp deliberately: the highest-risk surface of any slider (pointer, touch, keyboard, a11y) is delegated to the platform, while Rozie owns the author-side API, the range sort/clamp, the fill math, and the overlays. The cross-browser pseudo-element styling is shipped inside the component and gate-verified on WebKit and Firefox, so consumers never write it.

Feature matrix

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

CapabilityReact (Aria/Radix)Vue (Reka)Svelte (Melt)Solid (Kobalte)Angular (Material)Lit (none)noUiSlider@rozie-ui/slider
Headless ARIA slider⚠️ styled⚠️
Dual-thumb range✅ (range flag)
Built on native <input>⚠️✅ internal
Idiomatic component surface⚠️ hooks⚠️ buildershand-roll⚠️ wrapper<Slider>
Two-way value binding⚠️ value+onChangev-model⚠️ bind store⚠️ signal⚠️ wire CVA⚠️ eventsr-model:value (Angular CVA)
Vertical orientation⚠️orientation
Tick marks⚠️pipsmarks + mark slot
Value bubble / tooltip⚠️showValue + bubble slot
Imperative handle⚠️ varies⚠️ varies⚠️ varies⚠️ varies⚠️hand-roll⚠️✅ uniform focus/increment/decrement
Zero-config styling, re-skinnable⚠️ unstyled, wire it⚠️⚠️⚠️styled-only⚠️ ships CSS✅ CSS-var tokens + shadcn/Material/Bootstrap bridges
Same API on all 6 frameworks⚠️ vanilla + per-fw wrapper

Where Rozie wins today

  • First-class packages everywhere, including Lit / web components, which have no headless slider to begin with, and Angular, whose CDK ships no slider primitive at all (only the styled mat-slider). Both are categories the incumbents simply don't serve.
  • The same component surface everywhere. Where the ecosystem offers hooks (React), components (Vue/Solid), builders (Svelte), styled widgets (Angular Material), and a vanilla engine (noUiSlider), @rozie-ui/slider is one <Slider> to learn, document, and migrate: the same props, events, two-way value, slots, and uniform focus / increment / decrement handle.
  • A real two-way value. r-model:value reads and writes the value with no onChange → setState glue. Because value is the sole model: true prop, the Angular output additionally implements ControlValueAccessor, so a Slider is a form control ([formControl] / [(ngModel)] bind directly).
  • Built on the native <input type="range">. Drag (mouse and touch), keyboard, focus, role="slider", aria-value*, step/min/max, disabled, and RTL come from the platform, while Rozie owns the API, the range math, the fill, and the overlays.
  • Single and range in one component. range is a single boolean: off, a scalar single-thumb slider; on, a sorted [lo, hi] dual-thumb range. The two thumbs are two overlapping native inputs, each neighbour-clamped, so the array stays sorted however you drive it.
  • Zero-config styling that re-skins to any design system. Every rendered value is a --rozie-slider-* CSS custom property with a built-in fallback, plus ready-made token bridges for shadcn/ui, Material 3, and Bootstrap 5, and the cross-browser thumb/track pseudo-element styling that native range inputs require ships inside the component so you never hand-write it.

What Rozie defers

  • React Aria's accessibility depth. React Aria is the gold standard: locale-aware number formatting, exhaustive touch / pointer / virtual-cursor handling, and screen-reader testing across a large browser × AT matrix. @rozie-ui/slider leans on the native input's platform a11y and is gate-verified, but it does not match the breadth of React Aria's edge-case coverage.
  • Drag physics beyond the native input. A re-implemented <div> thumb (Radix, noUiSlider) can do things native range inputs cannot: pointer-precise dragging anywhere on the track, snap-to-mark drag, more than two thumbs, or non-linear scales. Rozie's native-input foundation trades that ceiling for free, identical platform input handling. More than two thumbs and non-linear scales are out of scope today.
  • It's a single component, not a primitive suite. React Aria, Radix, Kobalte, and Melt ship whole families: Slider alongside Menu, Dialog, Tabs, and more. Rozie ships slider (alongside its other @rozie-ui components), not a unified headless-primitive system.
  • @rozie-ui/slider is pre-1.0. The surface is stable and gate-verified, but the package is younger and less battle-tested than the multi-year incumbents. The full prop, event, slot, and handle tables live in the showcase + API reference.

Try it

The @rozie-ui/slider showcase + API reference documents the @rozie-ui/slider-* packages — one pre-compiled, per-framework install (npm i @rozie-ui/slider-react, etc.). There is no engine to import and no required CSS: the native-input behaviour, the cross-browser pseudo-element styling, 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-1.0 — APIs may change between minor versions.