react-wheel-scroller
v0.1.10
Published
React wheel-scroller pickers: calendar, datetime, range and select.
Maintainers
Readme
react-wheel-scroller
Touch-friendly wheel-scroller pickers for React — date, time, datetime, calendar, date-range, and select. Spinner-style controls you drop into forms, filters, or mobile bottom-sheets, with per-component subpaths so you only bundle the picker you use.
Features
- Six pickers, one library.
WsSelect,WsDate,WsTime,WsDatetime,WsCalendar, andWsRange(start/end) cover most date/time and list-selection needs. - Import only what you use. Per-component subpaths (
/calendar,/datetime,/range,/select) keep bundles tight;sideEffectsis scoped to presets and styles so tree-shaking stays effective. - Inline or overlay.
displayrenders a picker inline, as a bottom sheet, bubble, centered modal, or top bar — the same component, positioned to fit. - Desktop & touch.
touchUitoggles the touch-optimized layout; mouse-wheel and drag both work. - Controlled or uncontrolled. Use
value/defaultValuewithonChange/onSet, or drive it imperatively through the instance API (getVal()/setVal()). - Rich select. Single, multiple, or N-of, with grouping, live filtering, counters, and local or remote (
url) data sources. - Theming & i18n.
themeVariant(auto/light/dark), customtheme,rtl, and per-label text props for full localization. - Dual ESM + CJS, full TypeScript types. Ships
.d.tsfor every entry point plus a precompiled stylesheet — no build-time Sass required. - React 18 & 19 compatible.
react >= 18peer dependency.
Install
npm add react-wheel-scroller
# or: pnpm add react-wheel-scroller / yarn add react-wheel-scrollerreact >= 18 is a peer dependency. Import the stylesheet once at your app root:
import 'react-wheel-scroller/styles.css';Quickstart
import { WsSelect } from 'react-wheel-scroller/select';
import 'react-wheel-scroller/styles.css';
export function PriorityPicker() {
return (
<WsSelect
data={['Low', 'Medium', 'High']}
value="Medium"
onSet={(_event, inst) => console.log(inst.getVal())}
/>
);
}Import a component from its subpath for the tightest bundle; import styles.css once, anywhere above your pickers.
Entry points
| Import | Exports |
| --- | --- |
| react-wheel-scroller | WsCalendar, WsDatetime, WsDate, WsTime, WsRange, WsRangeStart, WsRangeEnd, WsSelect + prop types |
| react-wheel-scroller/calendar | WsCalendar |
| react-wheel-scroller/datetime | WsDatetime, WsDate, WsTime |
| react-wheel-scroller/range | WsRange, WsRangeStart, WsRangeEnd |
| react-wheel-scroller/select | WsSelect |
| react-wheel-scroller/styles.css | precompiled stylesheet (import once) |
Components
import { WsSelect } from 'react-wheel-scroller/select';
// Simple string list
<WsSelect data={['Low', 'Medium', 'High']} value="Medium" />
// Objects, grouped, multi-select, filterable, with a selection counter
<WsSelect
data={[
{ text: 'Alice', value: 1, group: 'Team A' },
{ text: 'Bob', value: 2, group: 'Team B' },
]}
dataText="text"
dataValue="value"
dataGroup="group"
group
select="multiple"
filter
counter
onSet={(_event, inst) => console.log(inst.getVal())}
/>
// Remote data source
<WsSelect
data={{ url: '/api/users', dataType: 'json', remoteFilter: true }}
dataText="name"
dataValue="id"
filter
/>select accepts 'single', 'multiple', or a number (N-of). Provide options as a string/object array via data, as <option> children, or from a remote url.
import { useState } from 'react';
import { WsDate, WsTime, WsDatetime } from 'react-wheel-scroller/datetime';
function BirthdayField() {
const [date, setDate] = useState<Date>();
return (
<WsDate
value={date}
min={new Date(2000, 0, 1)}
max={new Date()}
returnFormat="jsdate"
onSet={(_event, inst) => setDate(inst.getVal())}
/>
);
}
// 5-minute time steps, 24h format
<WsTime steps={{ minute: 5 }} timeFormat="HH:ii" />
// Combined date + time as a bottom sheet on touch devices
<WsDatetime
dateFormat="YYYY-MM-DD"
timeFormat="HH:ii"
display="bottom"
touchUi
/>returnFormat controls the value shape read back from getVal(): 'jsdate', 'iso8601', 'locale', or 'moment'. Bound the range with min / max.
import { WsCalendar } from 'react-wheel-scroller/calendar';
// Inline single-date grid
<WsCalendar
controls={['calendar']}
display="inline"
firstDay={1}
onSetDate={(_event, inst) => console.log(inst.getVal())}
/>
// Multi-select with marked days
<WsCalendar
controls={['calendar']}
select="multiple"
marked={[new Date(2026, 6, 4), new Date(2026, 6, 15)]}
/>
// Date + time in one picker
<WsCalendar controls={['calendar', 'time']} />controls composes the picker from 'calendar', 'date', and 'time'. select takes 'single', 'multiple', or a number; selectType switches between 'day' and 'week' selection.
import { WsRange, WsRangeStart, WsRangeEnd } from 'react-wheel-scroller/range';
// Two labelled inputs, opens as a bottom sheet
<WsRange controls={['calendar']} display="bottom" fromText="Check in" toText="Check out">
<WsRangeStart placeholder="From" />
<WsRangeEnd placeholder="To" />
</WsRange>
// Single input, inline, with a min/max span
<WsRange controls={['calendar']} display="inline" minRange={1} maxRange={30} />Nest WsRangeStart / WsRangeEnd to bind two of your own inputs; omit them and WsRange renders (or adopts) a single input. minRange / maxRange constrain the selectable span.
Styling
The package ships a precompiled stylesheet — import it once at your app root:
import 'react-wheel-scroller/styles.css';Adjust the color scheme per-picker with themeVariant ('auto' follows the OS), a custom theme, or rtl for right-to-left layouts.
Common props
Shared across the pickers (each component adds its own on top):
| Prop | Type | Purpose |
| --- | --- | --- |
| value / defaultValue | picker-specific | controlled / initial value |
| onChange | (event, inst) => void | fires while the wheel moves |
| onSet | (event, inst) => void | fires on confirm — read inst.getVal() |
| display | 'inline' \| 'bottom' \| 'center' \| 'top' \| 'bubble' | placement / presentation |
| touchUi | boolean | touch-optimized UI |
| themeVariant | 'auto' \| 'light' \| 'dark' | color scheme |
| disabled / readOnly | boolean | interaction state |
| min / max | Date \| string \| number | date/time bounds |
| returnFormat | 'iso8601' \| 'jsdate' \| 'locale' \| 'moment' | value shape from getVal() |
Full type definitions ship with the package (.d.ts per entry point).
Scripts
pnpm build— dual ESM+CJS +.d.ts(tsup) anddist/wheel-select.css(sass)pnpm typecheck/pnpm lint/pnpm test
Support
If react-wheel-scroller saves you time, consider sponsoring continued maintenance:
Even a one-time tip is appreciated — it pays for issue triage, version bumps, and the next feature.
License
MIT © Nazarii Kovtun
