Vanilla JS Slider

Pagiflow
Documentation

A powerful, dependency-free JavaScript slider with support for grids, thumbnails, auto-scroll, syncing, RTL, and much more. Every option documented with live demos.

30+ Options
12+Methods
0Dependencies
Possibilities

Installation

Include the Pagiflow script. No dependencies needed — pure vanilla JS.

Include Script
//1. Include Pagiflow
<script src="pagiflow.js"></script>
//2. Slider HTML
<div id="mySlider">
  <div>Slide 1</div>
  <div>Slide 2</div>
  <div>Slide 3</div>
</div>
//3. Initialize
<script>
const slider = Pagiflow('#mySlider');
</script>

Via CDN

The fastest way to use Pagiflow. Just copy these links into your HTML <head> and <body>.

jsDelivr CDN
<!-- 1. CSS (Place in <head>) -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/pagiflow/pagiflow@main/dist/css/pagiflow.min.css">

<!-- 2. JS (Place before </body>) -->
<script src="https://cdn.jsdelivr.net/gh/pagiflow/pagiflow@main/dist/js/pagiflow.min.js"></script>

direction

Controls the scroll axis of the slider. Use 'horizontal' (default) or 'vertical'.

Option Type Default Description
direction string 'horizontal' Scroll direction. 'horizontal' or 'vertical'.
Horizontal direction: 'horizontal'
01slide-1
02slide-2
03slide-3
04slide-4
05slide-5
06slide-6
const slider = Pagiflow('#mySlider', {
  direction: 'horizontal',
  nav: true
});
Vertical direction: 'vertical'
01slide-1
02slide-2
03slide-3
const slider = Pagiflow('#mySlider', {
  direction: 'vertical',
  nav: true
});

itemsPerSlide & slidesToScroll

Control how many items are visible at once and how many to scroll on each nav click.

Option Type Default Description
itemsPerSlide number 1 Number of visible slides at once.
slidesToScroll number 1 Steps to advance on next/prev.
startIndex number 0 Initial active slide index (zero-based).
3 items per slide itemsPerSlide: 3
01
02
03
04
05
06
const slider = Pagiflow('#mySlider', {
itemsPerSlide: 3,
slidesToScroll: 1,
gap: 12,
nav: true,
paginate: true
});

gap & height

Control spacing between slides and the viewport height.

Option Type Default Description
gap number 8 Gap between slides in pixels.
height string|number '30vh' Viewport height. E.g. 300, '300px', '50vh'. Used for vertical direction and fade mode.
Gap demo gap: 20
01
02
03
04
const slider = Pagiflow('#mySlider', {
itemsPerSlide: 2,
slidesToScroll: 1,
gap: 20,
nav: true,
height: 120,
});

loop

Enables infinite looping — the slider wraps around seamlessly using DOM clones.

Option Type Default Description
loop boolean false Infinite scroll loop. Adds clones at each end.
speed number 400 Transition duration in milliseconds.
animate boolean true Enable/disable transition animation.
Infinite loop loop: true
01loops endlessly →
02loops endlessly →
03loops endlessly →
const slider = Pagiflow('#mySlider', {
  itemsPerSlide: 1,
  loop: true,
  nav: true,
  speed: 400,
  });
  

paginate

Dot-based pagination with support for custom positioning.

Option Type Default Description
paginate boolean false Show pagination dots.
paginationPosition string|object null Custom position, e.g. 'bottom-center' or { bottom:10, left:'50%' }.
Pagination dots paginate: true
01click the dots below
02
03
04
const slider = Pagiflow('#mySlider', {
itemsPerSlide: 1,
nav: true,
paginate: true,
loop: true
});

autoplay

Automatically advance slides on a timer. Hover to pause.

Option Type Default Description
autoplay boolean false Enable autoplay.
autoplayDelay number 3000 Delay between slides in ms.
pauseOnHover boolean true Pause autoplay when mouse is over slider.
Autoplay autoplay: true, autoplayDelay: 2000
01hover to pause
02hover to pause
03hover to pause
04hover to pause
const slider = Pagiflow('#mySlider', {
itemsPerSlide: 1,
autoplay: true,
autoplayDelay: 2000,
pauseOnHover: true,
loop: true,
paginate: true
});

autoScroll

Continuous marquee-style scrolling using RAF. Perfect for logo strips and ticker bands.

Option Type Default Description
autoScroll boolean false Enable continuous auto-scroll mode.
autoScrollSpeed number 0.5 Pixels per frame scroll speed.
autoScrollDirection string 'left' 'left' or 'right'.
Infinite ticker autoScroll: true
Slide 01
Slide 02
Slide 03
Slide 04
Slide 05
Slide 06
Slide 07
Slide 08
Slide 09
Slide 10
const slider = Pagiflow('#mySlider', {
itemsPerSlide: 3,
autoScroll: true,
autoScrollSpeed: 0.5,
autoScrollDirection: 'left',
pauseOnHover: true
});

fade

Crossfade transition instead of sliding. Works only with single item view.

Option Type Default Description
fade boolean false Enable fade transition. Requires itemsPerSlide: 1 and horizontal direction.
Fade transition fade: true
01fade mode
02fade mode
03fade mode
const slider = Pagiflow('#mySlider', {
fade: true,
nav: true,
speed: 600,
});

grid

Display items in a CSS grid per slide page. Works like a paginated masonry.

Option Type Default Description
grid boolean false Enable grid mode.
gridColumns number 2 Number of columns in the grid.
itemsPerSlide number 1 Total items per slide page (rows × columns).
gridFill boolean false Fill incomplete last page with recycled items.
2-column grid grid: true, gridColumns: 2
01
02
03
04
05
06
const slider = Pagiflow('#mySlider', {
grid: true,
gridColumns: 2,
itemsPerSlide: 4, // 2 rows × 2 cols
gap: 10,
nav: true,
paginate: true
});

thumbnails

Show thumbnail strip that syncs with the main slider. Supports top, bottom, left, and right positions.

Option Type Default Description
thumbnails.enabled boolean false Enable thumbnails.
thumbnails.position string 'bottom' 'top', 'bottom', 'left', 'right'.
thumbnails.thumbWidth number|string 80 Width of each thumbnail.
thumbnails.gap number 5 Gap between thumbnails.
thumbnails.sidebarHeight string|number null Height for left/right sidebar mode.
Thumbnails bottom thumbnails.enabled: true
01thumbnail mode
02
03
04
05
06
07
08
09
10
const slider = Pagiflow('#mySlider', {
thumbnails: {
  enabled: true,
  position: 'bottom',
  thumbWidth: 90,
  gap: 6
},
  nav: true
});

centerMode

Centers the active slide with a peek of adjacent slides on both sides.

Option Type Default Description
centerMode boolean false Enable center mode.
centerPadding number|string 0 Side padding showing adjacent slides. E.g. 60 or '60px'.
Center mode centerMode: true, centerPadding: 60
01center focus
02
03
04
const slider = Pagiflow('#mySlider', {
centerMode: true,
centerPadding: 60,
loop: true,
nav: true
});

sync

Link two slider instances together — navigating one drives the other.

Option Type Default Description
sync string|instance null CSS selector or Pagiflow instance to sync with.
How it works: Both sliders are linked bidirectionally. Swipe or navigate one and the other follows. Great for thumbnail + main slider combos.
Sync two sliders sync: '#nav-slider'
01navigate this ↓
02
03
04
05
06
01
02
03
04
05
06
// Main slider  
const main = new Pagiflow('#main-slider', {
loop: true,
nav: true
});

// Nav slider (linked back)  
const nav = new Pagiflow('#nav-slider', {
itemsPerSlide: 3,
loop: true,
nav: true,
sync: '#main-slider'
});

rtl

Right-to-left mode for Arabic, Hebrew, and other RTL languages.

Option Type Default Description
rtl boolean false Right-to-left direction. Reverses swipe and translation.
RTL slider rtl: true
01← RTL direction
02
03
const slider = Pagiflow('#mySlider', {
rtl: true,
nav: true,
paginate: true,
});

keyboard

Enable keyboard arrow navigation when the slider is focused.

Option Type Default Description
keyboard boolean false Enable keyboard ←→ (horizontal) or ↑↓ (vertical) navigation. Home/End jump to first/last.
Keyboard nav keyboard: true
Try it: Click the slider below then press ← → arrow keys or Home/End.
01← → arrows
02
03
const slider = Pagiflow('#mySlider', {
keyboard: true,
nav: true,
});

lazyLoad

Defer image loading until slides come into view, using IntersectionObserver.

Option Type Default Description
lazyLoad boolean false Enable lazy loading. Images are replaced with shimmer until visible.
Lazy load lazyLoad: true
const slider = Pagiflow('#mySlider', {
lazyLoad: true,
nav: true,
});

responsive

Override any option at specific breakpoints. Keys are minimum widths in pixels.

Option Type Default Description
responsive object {} Map of breakpoint → options. Applied when window.innerWidth >= breakpoint.
Responsive breakpoints
const slider = Pagiflow('#mySlider', {
itemsPerSlide: 1,
gap: 8,
nav: true,
paginate: true,
responsive: {
  576: { itemsPerSlide: 2, gap: 12 },
  768: { itemsPerSlide: 3, gap: 16 },
  1200: { itemsPerSlide: 4, gap: 20, autoplay: true }
}
});
Note: Responsive options are deeply merged and re-evaluated on window resize (debounced 120ms).

Methods

All methods return this (chainable) unless noted otherwise.

Live method playground
01
02
03
04
05
→ output will appear here
.next()
Go to the next slide. Respects slidesToScroll and loop. No-ops if already at end without loop.
→ returns this (chainable)
.prev()
Go to the previous slide.
→ returns this (chainable)
.goTo(index, options?)
Jump to slide by zero-based index. Options: { silent: false, instant: false }. silent skips rendering; instant skips animation.
→ returns this
.play()
Resume autoplay. Sets autoplay: true and starts the timer.
→ returns this
.pause()
Pause autoplay or autoScroll animation frame.
→ returns this
.resume()
Resume from paused state. Works for both autoplay and autoScroll.
→ returns this
.togglePlayPause()
Toggle between play and pause.
→ returns this
.setOptions(newOptions, forceRebuild?)
Update options at runtime. Automatically rebuilds if structural options change (itemsPerSlide, gap, fade, etc.).
→ returns this
.html(content?)
Get or set slide HTML. Pass string/array to replace all slides and rebuild. Pass 'dom' to get DOM nodes. No args returns HTML string.
→ string | Node[] | this
.reInit(newOptions?)
Completely reinitialize the slider, optionally with new options. Rebuilds DOM wrapper and re-binds all events.
→ returns this
.destroy()
Tear down the slider completely. Removes wrapper DOM, unbinds all events, cancels timers and RAFs. Shows a loading spinner on the element.
→ void
.onSlideChange(callback)
Set a callback function that fires whenever the active slide changes. Receives the zero-based real index.
→ returns this

Instance Properties

Access slider state directly via the instance object.

Property Type Description
.index number Current active slide index (includes clones in loop mode). Use ._getRealIndex() for original item index.
.slides Node[] Array of all slide DOM elements (including clones).
.originalItems Node[] Clones of the original input DOM elements.
.wrapper Element The generated .pagiflow-wrapper element.
.slider Element The internal tracks/slider element.
.destroyed boolean True if the instance has been destroyed.

Chaining example

const slider = Pagiflow('#mySlider', {
loop: true,
});
// Methods are chainable
slider.goTo(2)
  .setOptions({ autoplay: true, autoplayDelay: 2000 }).play();
// After 5 seconds, pause
setTimeout(() => slider.pause(), 5000);

Events

Hook into slider lifecycle with the onSlideChange callback.

onSlideChange callback
01
02
03
→ navigate the slider to see events
const slider = Pagiflow('#mySlider', {
loop: true,
nav: true,
});
slider.onSlideChange((index) => {
  console.log(`Active slide: ${index}`);
});
// index is zero-based real index

All Options Reference

Complete list of all configuration options with types and defaults.

Option Type Default Description
direction string 'horizontal' Slide axis: 'horizontal' or 'vertical'.
itemsPerSlide number 1 Visible slides at once.
slidesToScroll number 1 Steps per navigation click.
gap number 8 Pixels between slides.
height string|number '30vh' Viewport height (vertical/fade mode).
startIndex number 0 Initial slide index.
loop boolean false Infinite loop with DOM clones.
speed number 400 Transition duration (ms).
animate boolean true Enable CSS transitions.
fade boolean false Crossfade instead of slide.
nav boolean false Show built-in prev/next buttons.
navDisabledEnd boolean false Disable (not hide) buttons at ends.
navigation object null External buttons { prev, next }.
prevIcon string '‹' Prev button HTML.
nextIcon string '›' Next button HTML.
prevPosition string|obj null Absolute position for prev button.
nextPosition string|obj null Absolute position for next button.
paginate boolean false Show pagination dots.
paginationPosition string|obj null Custom pagination position.
autoplay boolean false Auto-advance slides.
autoplayDelay number 3000 Delay between auto advances (ms).
pauseOnHover boolean true Pause autoplay on hover.
autoScroll boolean false Continuous marquee scrolling.
autoScrollSpeed number 0.5 Pixels per animation frame.
autoScrollDirection string 'left' 'left' or 'right'.
swipeThreshold number 60 Min swipe distance to trigger change.
grid boolean false Enable grid mode per slide.
gridColumns number 2 Grid column count.
gridFill boolean false Fill last page with recycled items.
thumbnails.enabled boolean false Show thumbnail strip.
thumbnails.position string 'bottom' top / bottom / left / right.
thumbnails.thumbWidth number 80 Thumbnail width in px.
thumbnails.gap number 5 Gap between thumbnails.
thumbnails.sidebarHeight string null Sidebar height for left/right mode.
centerMode boolean false Center active slide with peeking neighbors.
centerPadding number|string 0 Side padding for center mode.
rtl boolean false Right-to-left mode.
keyboard boolean false Arrow key navigation.
lazyLoad boolean false IntersectionObserver image lazy load.
sync string|inst null Selector or instance to sync with.
responsive object {} Breakpoint → options map.
html str|arr null Inject initial slide HTML content during initialization.
slider string null Selector used when passing a single object to Pagiflow().

Frequently Asked Questions

Common questions about installing, configuring, and using Pagiflow.

Download pagiflow.js from GitHub and add it with a single script tag — no build step, no npm, no bundler required. Add <script src="pagiflow.js"></script> before your closing </body> tag, then call Pagiflow('#mySlider', { nav: true }). That's the complete setup.
Yes. Pagiflow is framework-agnostic vanilla JavaScript. In React, initialize it inside a useEffect hook after the DOM has mounted. In Vue, use the mounted() lifecycle hook. Store the returned instance to call methods like slider.destroy() on component unmount. There are no official framework wrappers, but the plain JS API works cleanly in any environment.
Set autoplay: true and pauseOnHover: true in your options. Control the speed with autoplayDelay (default: 3000ms). For example: Pagiflow('#slider', { autoplay: true, autoplayDelay: 2500, pauseOnHover: true, loop: true }). You can also use the .play() and .pause() API methods to control autoplay programmatically.
Use the responsive option with breakpoint keys. Each key overrides any option at that viewport width. Example: Pagiflow('#slider', { itemsPerSlide: 1, responsive: { 576: { itemsPerSlide: 2 }, 992: { itemsPerSlide: 3, gap: 20 } } }). Options deep-merge, so you only need to specify values that change at each breakpoint. The slider re-evaluates on window resize with a 120ms debounce.
Use the autoScroll mode: Pagiflow('#ticker', { autoScroll: true, autoScrollSpeed: 1, autoScrollDirection: 'left', pauseOnHover: true, itemsPerSlide: 3, gap: 20 }). This uses requestAnimationFrame for buttery-smooth continuous scrolling — ideal for logo strips, partner banners, and news tickers. autoScrollSpeed is in pixels per frame.
Call slider.destroy() to cleanly remove all event listeners, DOM clones, and injected styles. The HTML will be restored to its original pre-init state. To re-initialize with different options, call Pagiflow('#slider', newOptions) after destroying. Alternatively, use slider.reInit() to destroy and reconstruct the same instance in-place, or slider.setOptions({ gap: 30 }) to update options at runtime without reinitializing.