Getting started
Choose the core library for custom wheel and trackpad interactions, or the Embla plugin for a carousel or picker with dragging, snapping, and wheel support.
- Core library — normalized gesture data in JavaScript or any framework.
- Embla integration — ready-made wheel support for React carousels and pickers.
Core library
Install wheel-gestures using your package manager:
npm install wheel-gesturesOr with Yarn:
yarn add wheel-gesturesUsage
Import WheelGestures from the package into your JavaScript/TypeScript file, create an instance and add the element you want the user to start a wheel gesture on.
import { WheelGestures } from 'wheel-gestures'
// create an instance per element
const wheelGestures = WheelGestures()
// find and observe the element the user can interact with
const element = window.document.querySelector('.slider')
wheelGestures.observe(element)
// add your event callback
wheelGestures.on('wheel', (wheelEventState) => {
//...
})The callback you added with .on('wheel', callback) now gets called for each recognized wheel event, with normalized information (eg. deltas) and metadata like velocity.
Avoid adding multiple elements with .observe() that are ancestors/descendants.
By default, wheel-gestures prevents the default (scrolling) on all axis. If you are only interested in allowing the user to perform a wheel gesture on one axis but keep the default behavior on the other, see the Options page and customize it.
Examples
Try the interactive demos or explore momentum detection in the wheel visualizer.
Embla integration for React
Install these packages in an existing React project. The plugin includes wheel-gestures as a dependency, so you do not need to install it separately unless you also use the core API directly. These are the compatible versions used by this site's carousel and time picker:
npm install embla-carousel@8.6.0 embla-carousel-react@8.6.0 embla-carousel-wheel-gestures@8.0.5import useEmblaCarousel from 'embla-carousel-react'
import { WheelGesturesPlugin } from 'embla-carousel-wheel-gestures'
export function Carousel() {
const [emblaRef, emblaApi] = useEmblaCarousel(
{ loop: false, skipSnaps: true },
[WheelGesturesPlugin()]
)
return (
<section aria-label="Example carousel">
<div ref={emblaRef} style={{ overflow: 'hidden' }}>
<div style={{ display: 'flex', touchAction: 'pan-y pinch-zoom' }}>
{[1, 2, 3].map((slide) => (
<div key={slide} style={{ flex: '0 0 100%', minWidth: 0 }}>
Slide {slide}
</div>
))}
</div>
</div>
<button type="button" onClick={() => emblaApi?.scrollPrev()}>Previous</button>
<button type="button" onClick={() => emblaApi?.scrollNext()}>Next</button>
</section>
)
}For a vertical, looping example with wheel support, try the time picker and copy its source.
Motivation
Due to the many differences between different browsers, operating systems and input devices, wheel events are not the easiest to work with. Which makes many developers neglect the wheel event as an input event to their web apps. Others use the wheel event already, but are overwhelmed by their complexity and handle them in a suboptimal way.
This small lib normalizes wheel events, provides useful meta data and an easier API.
License
Don't use this library to implement unresponsive page scroll jacking.
MIT.