@lifarl/react-scroll-snap-slider
v3.0.0-alpha
Published
A performant React Slider / Carousel Component with CSS Scroll Snapping, Intersection Observer and Accessibility.
Maintainers
Readme
react-scroll-snap-slider
A performant React Slider / Carousel Component with CSS Scroll Snapping, Intersection Observer and Accessibility.
Have a look at the Demo for the different variations.

Installation
yarn add @lifarl/react-scroll-snap-sliderNote: From v3.0.0, this library ships plain CSS (no styled-components). There are no styling peer dependencies.
Usage
import { Slider } from '@lifarl/react-scroll-snap-slider';
<Slider>
<div>Foo</div>
<div>Bar</div>
<div>Baz</div>
</Slider>See also examples in App.tsx
Styling / CSS
- Import once at app entry:
import '@lifarl/react-scroll-snap-slider/styles.css'. - All classes are prefixed with
.scs-to avoid global leaks. - Theming uses CSS variables set on any parent (or the component root):
--scs-gap(default8px)--scs-arrow-bg(default#fff)--scs-arrow-padding(default0.5em)--scs-arrow-radius(default4px)--scs-arrow-color(default#676767)--scs-arrow-size(default22px)--scs-scroll-behavior(defaultsmooth)--scs-snap-type(defaultx mandatory) — set tox proximityto reduce snap sensitivity on Chrome/Android--scs-snap-stop(defaultnormal) — set toalwaysto prevent skipping multiple slides per gesture--scs-touch-action(defaultpan-x) — adjust toautoif you need vertical gestures over the slider--scs-overscroll-behavior(defaultauto) — set tocontainto prevent scroll chaining to parent
Slots and class overrides are supported via classes on the Slider component:
<Slider
classes={{
root: 'my-carousel',
slider: 'my-slider',
list: 'my-list',
slide: 'my-slide',
nav: 'my-nav',
navPrev: 'my-nav-prev',
navNext: 'my-nav-next',
arrow: 'my-arrow',
}}
>
{...}
</Slider>Intersection Observer
Firing tracking events on css based sliders can be done with the intersection observer. Pass onSlideVisible to the Carousel and it will fire when a slide enters the viewport without triggering a rerender.
Props
onSlideVisible?: (index: number) => void // Callback that is triggered when a slide gets visible by a threshold of 0.5
renderCustomArrow?: ({
direction,
ref,
onClick,
}: CustomArrowProps) => JSX.Element // In case you want to use your own arrow design and logic
slidesPerPageSettings?: SlidesPerPageSettings // optionally for setting fixed amounts of slides for different viewports (min-width: 512px / 753px / 1232px)
slideWidth?: number // optionally for setting a fixed slide width
onScrollStart?: () => void // callback that triggers at the beginning of the scroll event
onScrollEnd?: (index: number) => void // callback that triggers at the end of the scroll event
children: React.ReactNode // put your slides here :)
className?: string // root class override
classes?: Partial<{
root: string
slider: string
list: string
slide: string
nav: string
navPrev: string
navNext: string
arrow: string
}>Browser Support
This lib does not include scroll snap polyfills to support older browsers like ie11. You would need to add them yourself. For more information see here.
Tuning Snap Feel (Android/Chrome)
Mobile browsers implement different scroll-snap heuristics. If the slider feels “too sensitive” on Android/Chrome (small flicks advance a slide, or gestures skip multiple slides), you can tune behavior via CSS variables:
/* Apply to your slider root */
.my-slider {
/* Reduce sensitivity */
--scs-snap-type: x mandatory; /* default */
/* Avoid skipping multiple slides */
--scs-snap-stop: always;
/* Optional axis + scroll chaining controls */
--scs-touch-action: pan-x; /* default */
--scs-overscroll-behavior: contain; /* keep scroll inside slider */
}Usage:
<Slider classes={{ root: 'my-slider' }}>
{...}
</Slider>Notes:
x proximityonly snaps when near a snap point, which typically reduces accidental snaps on Android compared tomandatory.scroll-snap-stop: alwaysensures the browser does not skip over intermediate slides during a fast flick.- If you need vertical page scrolling to take priority when swiping over the slider, set
--scs-touch-action: autoon the slider root.
