Lightweight Physics-Based Touch Carousel for JS & jQuery - DriftSlider

File Size: 360 KB
Views Total: 1
Last Update:
Publish Date:
Official Website: Go to website
License: MIT
   
Lightweight Physics-Based Touch Carousel for JS & jQuery - DriftSlider

DriftSlider is a lightweight JavaScript slider library that helps you create responsive, customizable, touch-friendly physics-based carousel sliders. It supports vanilla JS, jQuery, and TypeScript natively. 

Features:

  • Physics-Based Touch Interactions: Velocity tracking, configurable friction coefficients, and edge-bounce behavior produce natural swipe responses on both touch screens and pointer devices.
  • 4 Transition Effects: Slide (default), Fade (cross-fade), 3D Coverflow (depth, rotation, and scale), and Cards (stack, diagonal, and flip modes).
  • 9 Optional Modules: Navigation, Pagination, Autoplay, EffectFade, EffectCoverflow, EffectCards, Keyboard, A11y, and ScrollAos.
  • Each module is tree-shakeable. You bundle only what the project requires.
  • A mobile-first breakpoint system overrides slidesPerView, spaceBetween, loop, and other core options at defined min-width thresholds.
  • The A11y module adds ARIA roles, live regions, keyboard navigation, and prefers-reduced-motion support out of the box.

Use Cases:

  • Create touch‑friendly product carousels with smooth swiping, perfect for mobile e‑commerce sites.
  • Use the Coverflow or Cards effect to present design work.
  • Build auto‑playing hero sliders with fade transitions and pause‑on‑hover for content‑heavy landing pages.
  • Implement a step‑by‑step card stack that users can swipe through, complete with progress pagination.

How To Use It:

1. Install DriftSlider package with NPM and import it into your JS project:

# NPM
$ npm install drift-slider
// Import the core class
import DriftSlider from 'drift-slider';

// Import only the modules your project requires
import { Navigation, Pagination, Autoplay } from 'drift-slider/modules';

// Import the CSS bundle
import 'drift-slider/css/bundle';

2. Or load the core JavaScript & CSS files directly in the document.

<!-- Core stylesheet -->
<link rel="stylesheet" href="/dist/drift-slider-bundle.css">

<!-- UMD bundle — exposes DriftSlider as a global object -->
<script src="/dist/drift-slider.umd.js"></script>

3. Create the basic markup for your carousel slider. The container holds a track, a list, and individual slide elements.

<section class="drift-slider" aria-label="Product Gallery">
  <div class="drift-track">
    <ul class="drift-list">
      <li class="drift-slide">Item 1</li>
      <li class="drift-slide">Item 2</li>
      <li class="drift-slide">Item 3</li>
    </ul>
  </div>

  <!-- Optional: prev/next arrow buttons -->
  <button class="drift-arrow drift-arrow--prev" type="button"></button>
  <button class="drift-arrow drift-arrow--next" type="button"></button>

  <!-- Optional: pagination container -->
  <div class="drift-pagination"></div>
</section>

4. Initialize the carousel slider.

// Vanilla JavaScript/ESM
const productSlider = new DriftSlider('.drift-slider', {

  // Register selected modules as an array
  modules: [Navigation, Pagination, Autoplay],

  // Show 1 slide at a time on mobile
  slidesPerView: 1,

  // 16px gap between slides 
  spaceBetween: 16,

  // Infinite loop mode via slide cloning
  loop: true,

  // Show a grab cursor on hover
  grabCursor: true,

  // Navigation arrows using default DOM placement
  navigation: true,

  // Bullet-style pagination with clickable dots
  pagination: {
    type: 'bullets',
    clickable: true,
  },

  // Auto-advance every 4 seconds, pause on hover
  autoplay: {
    enabled: true,
    delay: 4000,
    pauseOnMouseEnter: true,
  },
});
// As a jQuery Plugin
$('.drift-slider').driftSlider({
  // options here
});
// Using the UMD / CDN Build
// All modules are available on the global DriftSlider object
const { DriftSlider: Slider, Navigation, Pagination, Autoplay } = DriftSlider;

const heroSlider = new Slider('#hero-carousel', {
  modules: [Navigation, Pagination, Autoplay],
  slidesPerView: 1,
  loop: true,
  navigation: true,
  autoplay: { enabled: true, delay: 5000 },
});

5. The breakpoint system uses a mobile-first approach. Each key represents a min-width in pixels.

const gallerySlider = new DriftSlider('.drift-slider', {
  // Base config: 1 slide on small screens
  slidesPerView: 1,
  spaceBetween: 12,

  breakpoints: {
    // At 768px and wider: show 2 slides
    768: {
      slidesPerView: 2,
      spaceBetween: 20,
    },
    // At 1200px and wider: show 4 slides
    1200: {
      slidesPerView: 4,
      spaceBetween: 24,
    },
  },
});

// Listen for breakpoint changes
gallerySlider.on('breakpoint', (s, bp) => {
  console.log('Active breakpoint:', bp, '— slidesPerView:', s.params.slidesPerView);
});

6. Available transition effects.

// Fade Effect
import { EffectFade } from 'drift-slider/modules';

const fadeSlider = new DriftSlider('.drift-slider', {
  modules: [EffectFade],

  // Activate the fade effect (module required)
  effect: 'fade',

  fadeEffect: {
    // Both outgoing and incoming slides animate simultaneously
    crossFade: true,
  },
});

// 3D Coverflow Effect
import { EffectCoverflow } from 'drift-slider/modules';

const coverflowSlider = new DriftSlider('.drift-slider', {
  modules: [EffectCoverflow],

  effect: 'coverflow',
  centeredSlides: true, // Required for the coverflow layout to look correct
  slidesPerView: 3,

  coverflowEffect: {
    depth: 250, // Z-axis depth in pixels
    rotate: 40, // Side slide rotation in degrees
    scale: 0.8, // Side slides scale down to 80%
    overlay: true,
    overlayColor: 'rgba(0,0,0,0.45)', // Darkening overlay on side slides
  },
});


// Cards Effect
import { EffectCards } from 'drift-slider/modules';

const testimonialSlider = new DriftSlider('.drift-slider', {
  modules: [EffectCards],

  effect: 'cards',

  cardsEffect: {
    mode: 'stack', // 'stack' | 'diagonal' | 'flip'
    direction: 'tl-br', // Stack offset direction: top-left to bottom-right
    offsetX: 20,
    offsetY: 20,
    scale: 0.9, // Cards behind the active one scale to 90%
    shadow: true,
    shadowBlur: 24,
  },
});

7. All available configuration options.

  • direction (string): Scroll axis. Accepts 'horizontal' or 'vertical'. Default: 'horizontal'.
  • slidesPerView (number): Number of slides visible simultaneously. Default: 1.
  • spaceBetween (number): Gap between slides in pixels. Default: 0.
  • centeredSlides (boolean): Centers the active slide in the viewport. Default: false.
  • slidesPerGroup (number): Number of slides advanced per navigation action or swipe. Default: 1.
  • speed (number): Transition duration in milliseconds. Default: 400.
  • easing (string): CSS easing function for transitions. Default: 'ease-out'.
  • loop (boolean): Activates infinite loop mode via slide cloning. Default: false.
  • loopAdditionalSlides (number): Extra clone slides appended for smoother loops. Default: 0.
  • initialSlide (number): Zero-based index of the starting slide. Default: 0.
  • grabCursor (boolean): Shows a grab cursor over the slider on hover. Default: false.
  • watchOverflow (boolean): Locks the slider when slides don't exceed the container width. Default: true.
  • effect (string): Transition effect. Accepts 'slide', 'fade', 'coverflow', or 'cards'. The corresponding effect module must be registered. Default: 'slide'.
  • modules (array): Array of module factory functions to register on the instance. Default: [].
  • physics.friction (number): Velocity damping factor between 0 and 1. Higher values preserve momentum longer. Default: 0.92.
  • physics.attraction (number): Pull force toward the nearest snap point. Higher values snap faster. Default: 0.025.
  • physics.bounceRate (number): Spring bounce intensity when the slider reaches an edge. Default: 0.5.
  • touchEnabled (boolean): Activates touch and mouse drag interaction. Default: true.
  • threshold (number): Minimum drag distance in pixels before movement starts. Default: 5.
  • touchAngle (number): Maximum angle in degrees from horizontal that the library accepts as a swipe gesture. Default: 45.
  • shortSwipes (boolean): Allows short, quick gestures to advance slides. Default: true.
  • longSwipesRatio (number): Fraction of the slider width that must be dragged to trigger a long-swipe transition. Default: 0.5.
  • followFinger (boolean): Slide tracks the pointer position in real time during drag. Default: true.
  • resistance (boolean): Adds drag resistance at the first and last slide. Default: true.
  • resistanceRatio (number): Resistance strength. Lower values create stronger resistance. Default: 0.85.
  • containerClass (string): Class on the container element. Default: 'drift-slider'.
  • trackClass (string): Class on the track element. Default: 'drift-track'.
  • listClass (string): Class on the list element. Default: 'drift-list'.
  • slideClass (string): Class on each slide element. Default: 'drift-slide'.
  • slideActiveClass (string): Class on the active slide. Default: 'drift-slide--active'.
  • slidePrevClass (string): Class on the slide before the active one. Default: 'drift-slide--prev'.
  • slideNextClass (string): Class on the slide after the active one. Default: 'drift-slide--next'.
  • slideVisibleClass (string): Class on all slides currently in the viewport. Default: 'drift-slide--visible'.
  • slideCloneClass (string): Class on cloned slides in loop mode. Default: 'drift-slide--clone'.
  • navigation.nextEl (string | HTMLElement | null): Selector or element for the next button. Default: null.
  • navigation.prevEl (string | HTMLElement | null): Selector or element for the previous button. Default: null.
  • navigation.disabledClass (string): Class applied to disabled arrows. Default: 'drift-arrow--disabled'.
  • navigation.hiddenClass (string): Class applied to hidden arrows. Default: 'drift-arrow--hidden'.
  • navigation.prevStyle (object | null): Inline styles applied to the prev button. Default: null.
  • navigation.nextStyle (object | null): Inline styles applied to the next button. Default: null.
  • pagination.el (string | HTMLElement | null): Selector or element for the pagination container. Default: null.
  • pagination.type (string): Display style. Accepts 'bullets', 'fraction', or 'progressbar'. Default: 'bullets'.
  • pagination.clickable (boolean): Bullet clicks navigate to the corresponding slide. Default: true.
  • pagination.bulletClass (string): Class on each bullet element. Default: 'drift-pagination__bullet'.
  • pagination.bulletActiveClass (string): Class on the active bullet. Default: 'drift-pagination__bullet--active'.
  • pagination.currentClass (string): Class on the current number in fraction mode. Default: 'drift-pagination__current'.
  • pagination.totalClass (string): Class on the total count element in fraction mode. Default: 'drift-pagination__total'.
  • pagination.progressClass (string): Class on the progress bar fill element. Default: 'drift-pagination__progress'.
  • pagination.renderBullet (function | null): Custom render function for bullets. Receives (index, className) and must return an HTML string. Default: null.
  • pagination.renderFraction (function | null): Custom render function for fraction display. Receives (currentClass, totalClass). Default: null.
  • pagination.renderProgressbar (function | null): Custom render function for the progress bar. Receives (progressClass). Default: null.
  • pagination.style (object | null): Inline styles for the pagination container. Default: null.
  • pagination.bulletStyle (object | null): Inline styles for each bullet. Default: null.
  • pagination.bulletActiveStyle (object | null): Inline styles for the active bullet. Default: null.
  • pagination.progressStyle (object | null): Inline styles for the progress bar fill. Default: null.
  • autoplay.enabled (boolean): Activates autoplay on init. Default: false.
  • autoplay.delay (number): Milliseconds between slide advances. Default: 3000.
  • autoplay.disableOnInteraction (boolean): Stops autoplay after the user interacts with the slider. Default: true.
  • autoplay.pauseOnMouseEnter (boolean): Pauses autoplay while the cursor is over the slider. Default: false.
  • autoplay.stopOnLastSlide (boolean): Stops at the last slide in non-loop mode. Default: false.
  • autoplay.reverseDirection (boolean): Autoplay advances to the previous slide. Default: false.
  • fadeEffect.crossFade (boolean): The outgoing and incoming slides animate simultaneously. Default: false. Requires effect: 'fade'.
  • coverflowEffect.depth (number): Z-axis depth offset in pixels (translateZ). Default: 200.
  • coverflowEffect.rotate (number): Rotation angle of side slides in degrees. Default: 30.
  • coverflowEffect.scale (number): Scale factor applied to side slides. Default: 0.85.
  • coverflowEffect.stretch (number): Additional horizontal offset between slides in pixels. Default: 0.
  • coverflowEffect.modifier (number): Global multiplier applied to all effect values. Default: 1.
  • coverflowEffect.overlay (boolean): Adds a darkening overlay on side slides. Default: true.
  • coverflowEffect.overlayColor (string): Overlay color value. Default: 'rgba(0,0,0,0.4)'.
  • coverflowEffect.opacity (number): Opacity of side slides. Default: 0.6.
  • coverflowEffect.activeOpacity (number): Opacity of the active center slide. Default: 1.
  • coverflowEffect.align (string): Vertical alignment of slides. Accepts 'center', 'top', 'bottom'. Default: 'center'.
  • coverflowEffect.fillCenter (boolean): Stretches the active slide to fill the center area. Default: false.
  • coverflowEffect.cropSides (boolean): Crops side slides at the container edge. Default: false.
  • coverflowEffect.staggerY (number): Vertical stagger offset in pixels. Default: 0.
  • coverflowEffect.visibleSides (string): Controls which side slides render. Accepts 'both', 'prev', 'next'. Default: 'both'.
  • cardsEffect.mode (string): Card stacking mode. Accepts 'stack', 'diagonal', 'flip'. Default: 'stack'.
  • cardsEffect.direction (string): Offset direction for the stack. Accepts 'tl-br', 'bl-tr', 'tr-bl', 'br-tl', 'auto'. Default: 'tl-br'.
  • cardsEffect.offsetX (number): Horizontal pixel offset between stacked cards. Default: 30.
  • cardsEffect.offsetY (number): Vertical pixel offset between stacked cards. Default: 30.
  • cardsEffect.scale (number): Scale factor for cards behind the active card. Default: 0.92.
  • cardsEffect.opacity (number): Opacity of cards behind the active card. Default: 0.85.
  • cardsEffect.diagonalMultiplier (number): Offset multiplier in diagonal mode. Default: 2.5.
  • cardsEffect.flipAxis (string): Rotation axis in flip mode. Accepts 'Y' or 'X'. Default: 'Y'.
  • cardsEffect.overlay (boolean): Adds a darkening overlay on stacked cards. Default: true.
  • cardsEffect.overlayColor (string): Color of the card overlay. Default: 'rgba(0,0,0,0.15)'.
  • cardsEffect.shadow (boolean): Adds drop shadows to cards. Default: true.
  • cardsEffect.shadowColor (string): Shadow color. Default: 'rgba(0,0,0,0.25)'.
  • cardsEffect.shadowBlur (number): Shadow blur radius in pixels. Default: 20.
  • keyboard.enabled (boolean): Activates keyboard arrow-key navigation. Default: false.
  • keyboard.onlyInViewport (boolean): Restricts key event handling to when the slider is visible in the viewport. Default: true.
  • a11y.enabled (boolean): Activates all accessibility enhancements. Default: true.
  • a11y.prevSlideMessage (string): aria-label for the previous button. Default: 'Previous slide'.
  • a11y.nextSlideMessage (string): aria-label for the next button. Default: 'Next slide'.
  • a11y.firstSlideMessage (string): Announced when the first slide is reached. Default: 'This is the first slide'.
  • a11y.lastSlideMessage (string): Announced when the last slide is reached. Default: 'This is the last slide'.
  • a11y.paginationBulletMessage (string): aria-label template for pagination bullets. Use {{index}} as the placeholder. Default: 'Go to slide {{index}}'.
  • a11y.containerMessage (string | null): aria-label for the slider container. Default: null.
  • a11y.containerRoleDescription (string): aria-roledescription for the container. Default: 'carousel'.
  • a11y.slideRole (string): ARIA role assigned to each slide element. Default: 'group'.
  • a11y.slideRoleDescription (string): aria-roledescription for each slide. Default: 'slide'.
  • a11y.liveRegion (boolean): Creates an aria-live="polite" region that announces slide changes. Default: true.
  • scrollAos.enabled (boolean): Activates scroll-triggered animations. Default: false.
  • scrollAos.animation (string): AOS animation class applied to the container. Default: 'fade-up'.
  • scrollAos.duration (number): Animation duration in milliseconds. Default: 800.
  • scrollAos.offset (number): Scroll offset in pixels before the animation fires. Default: 120.
  • scrollAos.once (boolean): Animates only the first time the element scrolls into view. Default: true.
  • scrollAos.setContainerAos (boolean): Automatically sets data-aos on the slider container. Default: true.
  • scrollAos.slideAnimation (string | null): AOS animation class applied to individual slides. Default: null.
  • scrollAos.slideDelay (number): Stagger delay between slide animations in milliseconds. Default: 100.
  • scrollAos.refreshOnChange (boolean): Calls AOS.refresh() on each slide change. Default: false.
const coverflowSlider = new DriftSlider('.drift-slider', {
  // Direction
  direction: 'horizontal', // 'horizontal' | 'vertical'

  // Slides
  slidesPerView: 1,
  spaceBetween: 0,
  centeredSlides: false,
  slidesPerGroup: 1,

  // Speed & animation
  speed: 400,
  easing: 'ease-out',

  // Physics-based touch (Keen-Slider / Flickity inspired)
  physics: {
    friction: 0.92,
    attraction: 0.025,
    bounceRate: 0.5,
  },

  // Touch / Drag
  touchEnabled: true,
  threshold: 5,
  touchAngle: 45,
  shortSwipes: true,
  longSwipesRatio: 0.5,
  followFinger: true,
  resistance: true,
  resistanceRatio: 0.85,

  // Loop
  loop: false,
  loopAdditionalSlides: 0,

  // Autoplay (module)
  autoplay: false,

  // Navigation (module)
  navigation: false,

  // Pagination (module)
  pagination: false,

  // Keyboard (module)
  keyboard: false,

  // Accessibility (module)
  a11y: true,

  // Effect
  effect: 'slide', // 'slide' | 'fade'

  // Breakpoints
  breakpoints: null,

  // Initial slide
  initialSlide: 0,

  // CSS classes
  containerClass: 'drift-slider',
  trackClass: 'drift-track',
  listClass: 'drift-list',
  slideClass: 'drift-slide',
  slideActiveClass: 'drift-slide--active',
  slidePrevClass: 'drift-slide--prev',
  slideNextClass: 'drift-slide--next',
  slideVisibleClass: 'drift-slide--visible',
  slideCloneClass: 'drift-slide--clone',

  // Grab cursor
  grabCursor: false,

  // Observer
  watchOverflow: true,

  // Modules
  modules: [],

  // Callbacks
  on: null,
});

8. API methods:

// Slide to a specific zero-based index
// Second param overrides the transition speed in ms
// Pass false as the third param to suppress slideChange events
slider.slideTo(2, 600, true);

// Advance one slide forward (respects slidesPerGroup)
slider.slideNext();

// Go back one slide
slider.slidePrev();

// Snap to the nearest snap point from the current drag position
slider.slideToClosest();

// Force a full layout recalculation
// Call this after dynamically adding or removing slides
slider.update();

// Destroy the instance and remove all event listeners
// Pass true to also remove inline styles from slides and the list element
slider.destroy(true);

// Re-enable a previously disabled slider
slider.enable();

// Lock the slider — ignores touch, drag, and navigation
slider.disable();

// Methods that return the instance are chainable
slider.slideNext().slideNext().slidePrev();

// Remove a specific event listener
const onChange = (s) => console.log(s.activeIndex);
slider.on('slideChange', onChange);
slider.off('slideChange', onChange);

// Remove all listeners for a given event
slider.off('slideChange');

// Manually fire an event on the instance
slider.emit('slideChange', slider);

// Start autoplay programmatically
slider.autoplay.start();

// Stop autoplay completely
slider.autoplay.stop();

// Pause the interval without resetting it
slider.autoplay.pause();

// Resume after a pause
slider.autoplay.resume();

// Returns true if autoplay is currently running
if (slider.autoplay.running()) {
  console.log('Autoplay is active');
}

// Recalculate the disabled/enabled state of both arrows
slider.navigation.update();

// Attach and show navigation arrows
slider.navigation.enable();

// Remove and hide navigation arrows
slider.navigation.disable();

// Refresh the active bullet, fraction, or progress bar display
slider.pagination.update();

// Re-render the entire pagination DOM
slider.pagination.render();

// Direct reference to the pagination container element
console.log(slider.pagination.el);

// Activate arrow-key navigation at runtime
slider.keyboard.enable();

// Deactivate keyboard navigation
slider.keyboard.disable();

9. Events:

// Fires after the slider fully initializes
slider.on('init', (s) => {
  console.log('Slider initialized with', s.slides.length, 'slides');
});

// Fires when the active slide index changes
slider.on('slideChange', (s) => {
  console.log('Active slide:', s.realIndex);
});

// Fires when a transition animation starts
slider.on('slideChangeTransitionStart', (s) => {
  console.log('Transition started from:', s.previousIndex);
});

// Fires when a transition animation finishes
slider.on('slideChangeTransitionEnd', (s) => {
  console.log('Transition complete at:', s.activeIndex);
});

// Fires on pointer or touch down
slider.on('touchStart', (s, event) => {
  console.log('Drag started');
});

// Fires while the user is dragging
slider.on('touchMove', (s, event) => {
  console.log('Dragging...');
});

// Fires on pointer or touch release
slider.on('touchEnd', (s, event) => {
  console.log('Drag ended');
});

// Fires as the slider's overall progress updates (0 to 1)
slider.on('progress', (s, p) => {
  console.log('Progress value:', p.toFixed(2));
});

// Fires when the slider reaches the first slide
slider.on('reachBeginning', (s) => {
  console.log('At the beginning');
});

// Fires when the slider reaches the last slide
slider.on('reachEnd', (s) => {
  console.log('At the end');
});

// Fires on window resize after the slider recalculates its layout
slider.on('resize', (s) => {
  console.log('Resized — container size:', s.containerSize);
});

// Fires when the active responsive breakpoint changes
slider.on('breakpoint', (s, bp) => {
  console.log('Breakpoint changed to:', bp);
});

// Fires every time the translate value is set
slider.on('setTranslate', (s, translate) => {
  console.log('Translate:', translate);
});

// Fires every time the transition duration is set
slider.on('setTransition', (s, duration) => {
  console.log('Transition duration:', duration + 'ms');
});

// Fires after update() recalculates the layout
slider.on('update', (s) => {
  console.log('Layout recalculated');
});

// Autoplay lifecycle events
slider.on('autoplayStart', (s) => console.log('Autoplay started'));
slider.on('autoplayStop', (s) => console.log('Autoplay stopped'));
slider.on('autoplayPause', (s) => console.log('Autoplay paused'));
slider.on('autoplayResume', (s) => console.log('Autoplay resumed'));

// Fires before the destroy process begins
slider.on('beforeDestroy', (s) => {
  console.log('About to destroy');
});

// Fires after the slider instance is destroyed
slider.on('destroy', (s) => {
  console.log('Slider destroyed');
});

This awesome jQuery plugin is developed by hanfour. For more Advanced Usages, please check the demo page or visit the official website.