Documentation

Markup

Every direct child of the container is a slide. No wrapper elements needed.

<div class="slider">
  <div>Slide 1</div>
  <div>Slide 2</div>
  <div>Slide 3</div>
</div>

Initialising

import Mozert from '@mozert-studio/mozert-slider';
const slider = new Mozert('.slider', { dots: true, autoplay: true });

Options

Defaults come from Mozert.defaults. Change them globally by assigning to it.

OptionDefaultDescription
accessibilitytrueAdds ARIA roles/labels and keyboard support.
adaptiveHeightfalseAnimate the list height to the active slide (single-slide views).
appendArrowsnullElement or selector to place both arrows in (for example a control bar under the slider). Default: inside the slider.
appendDotsnullElement or selector to place the dots in. Default: inside the slider, under the slides.
arrowstrueShow previous/next arrows.
asNavFornullSelector of another slider to keep in sync (thumbnails, controllers).
autoplayfalseStart automatically.
autoplayReversefalseAutoplay moves backwards.
autoplaySpeed3000Delay between slides in ms.
bleedfalsetrue, "left" or "right". Slides overflow the container towards the viewport edge; the first and last slide still align with the container. Forces infinite: false and sets overflow-x: clip on body so the page gets no horizontal scrollbar.
cardsEffect{…}perSlideOffset, perSlideRotate, rotate, visible.
centerModefalseCentre the active slide; neighbours peek.
centerPadding"50px"Width of the peek on each side in centerMode: "50px" or "10%". Change it per screen size with responsive.
coverflowEffect{…}rotate, depth, stretch, scale, modifier, lift (raises background cards), fade (dims them).
creativeEffect{…}prev / next with translate, rotate, opacity, scale; limitProgress.
cssEase"ease"CSS easing for transitions.
cubeEffect{…}perspective.
customPagingnullFunction (slider, i) returning markup for dot i.
disableOnInteractionfalseStop autoplay for good after the user clicks, taps or drags.
dotsfalseShow dots.
dotsClass"mozert-dots"Class of the dots list.
dragThreshold6Pixels to move before a drag starts.
draggabletrueMouse dragging (touch is controlled by swipe).
easing"linear"Easing used when useCSS is false.
edgeFriction0.15Resistance when dragging past the first/last slide (non-infinite).
edgePadding0Space before the first and after the last slide (px or %).
effect"slide"slide, fade, coverflow, cube, flip, cards, creative or expand.
expandEffect{…}extra: how much wider the active card gets, as a multiple of a slide width (default 1.4). The card inside each slide is resized, so give slides a single child element.
fadefalseShortcut for effect: "fade".
flipEffect{…}perspective, limitRotation.
focusOnSelectfalseClicking a slide makes it active.
freeModefalseDrag with momentum and no snapping. Accepts an options object.
fullscreenfalseAdd a fullscreen toggle button.
globalKeyboardfalseArrow keys control the slider while it is in the viewport.
hashNavigationfalsetrue or { watchState, replaceState, prefix }. Slides use data-hash.
infinitetrueLoop forever using clones.
initialSlide0First slide index.
labelsnullObject overriding built-in ARIA strings (translations).
lazyLoad"ondemand"ondemand or progressive.
lightboxfalseClick a slide to open it full screen. true or { zoom, loop, maxZoom }.
magnifierfalseHover zoom for product galleries. true or { zoom: 2.2, button: true, active: false }. A button in the top right corner turns it on and off; data-zoom on an image loads a sharper file.
marqueefalse{ speed, pauseOnHover, direction }. Continuous ticker.
mobileFirstfalseBreakpoints are min-width instead of max-width.
mousewheelfalsetrue or { sensitivity, forceToAxis, releaseOnEdges, thresholdTime }.
nextArrownullYour own markup (an HTML string) or an element for the next arrow. It gets the class mozert-next and works as the next button.
onnullEvent handlers object, e.g. { afterChange(s, i) {} }.
paginationfalse{ el, type, clickable, renderBullet, ... }. Types: bullets, dynamic, fraction, progressbar, custom.
parallaxfalseEnable data-parallax-* attributes.
pauseOnDotsHoverfalsePause autoplay when hovering the dots.
pauseOnFocustruePause autoplay on keyboard focus.
pauseOnHovertruePause autoplay on hover.
prevArrownullYour own markup (an HTML string) or an element for the previous arrow. It gets the class mozert-prev and works as the previous button.
respectReducedMotiontrueDisable autoplay/animation for prefers-reduced-motion users.
respondTo"window"window, slider or min width used for breakpoints.
responsivenullArray of { breakpoint, settings }. settings: "destroy" turns the slider off at that breakpoint.
rows1Grid rows.
rtlfalseRight-to-left layout for Arabic, Hebrew, Urdu and other RTL pages. Slides start from the right, swipe, arrows and keyboard arrows are reversed, and dir="rtl" is set on the slider.
scrollDrivenfalsePage scroll moves the slides while the slider sticks to the top. true or { fill, speed, top, offset, bottom, step }. Horizontal, non-looping sliders only.
scrollbarfalsetrue or { el, draggable, hide }.
slide""Selector of the slide elements inside the container.
slideWidth0Fixed slide width in px; slides per view is computed.
slidesPerRow1Columns per page when rows > 1.
slidesToScroll1Slides per move.
slidesToShow1Slides visible (fractional allowed).
spaceBetween0Gap between slides in px.
speed300Transition time in ms.
stopOnLastSlidefalseStop autoplay after the last slide (non-infinite).
swipetrueTouch swiping.
swipeToSlidefalseLand on the slide nearest the release point.
thumbsfalsetrue builds a thumbnail strip below the slider; a selector or element uses your own strip; { el, count, options } for more control. Keeps both sliders in sync.
touchMovetrueSlides follow the finger.
touchRatio1Drag distance multiplier.
touchThreshold5Fraction of the width needed to change slide (width / value).
useCSStrueCSS transitions (false = JS animation).
useTransformtrueUse transform instead of left/top.
variableWidthfalseSlides keep their own width.
verticalfalseVertical slider.
verticalSwipingfalseVertical swipe gestures.
videoAutoplayfalsePlay the active slide's <video>. { wait } holds autoplay until it ends.
virtualfalse{ slides, renderSlide, addSlidesBefore, addSlidesAfter, cache }.
waitForAnimatetrueIgnore input while animating.
zIndex1000Base z-index for stacked effects.
zoomfalsetrue or { max, min, toggle, step }.

Responsive

Breakpoints are max-width by default; add mobileFirst: true for min-width breakpoints. Only the matching breakpoint's settings override the base.

new Mozert('.slider', {
  slidesToShow: 4,
  responsive: [
    { breakpoint: 1024, settings: { slidesToShow: 3 } },
    { breakpoint: 600,  settings: { slidesToShow: 1.5, spaceBetween: 8 } },
    { breakpoint: 400,  settings: 'destroy' }   // destroy below 400px
  ]
});

Effects

Choose with effect. Each effect reads its own options object. They respond to dragging, so the slide follows your finger.

new Mozert('.slider', {
  effect: 'coverflow',
  slidesToShow: 3,
  coverflowEffect: { rotate: 40, depth: 140, stretch: 0, modifier: 1, scale: 0.8, lift: 60, fade: 0.2 }  // lift raises background cards, fade dims them
});

// Expanding cards: the active card opens wide, the others stay narrow
new Mozert('.slider', {
  effect: 'expand',
  slidesToShow: 4.4,
  expandEffect: { extra: 1.4 }  // how much wider the active card gets (1.4 = 140% of a slide)
});

new Mozert('.slider', {
  effect: 'creative',
  creativeEffect: {
    prev: { translate: ['-120%', 0, -300], rotate: [0, 0, -6], opacity: 0 },
    next: { translate: ['100%', 0, 0] }
  }
});
Cube, flip, cards, creative and fade show one slide at a time (slidesToShow is forced to 1). Coverflow and expand centre the active slide and support several visible slides.

Pagination

new Mozert('.slider', {
  pagination: {
    el: '#my-pagination',        // optional, otherwise created inside the slider
    type: 'bullets',             // 'bullets' | 'dynamic' | 'fraction' | 'progressbar' | 'custom'
    clickable: true,
    renderBullet: (i, cls) => '<button class="' + cls + '">' + (i + 1) + '</button>',
    renderCustom: (slider, current, total) => current + ' of ' + total   // for type: 'custom'
  },
  scrollbar: { draggable: true, hide: false }
});

dots (simple dot list) and pagination (typed pagination) are independent; use either.

Free mode, mousewheel, keyboard

new Mozert('.slider', {
  freeMode: { momentum: true, momentumRatio: 1, sticky: false },
  mousewheel: { sensitivity: 1, releaseOnEdges: true },
  globalKeyboard: true,
  slidesToShow: 3.2, infinite: false
});

Parallax

<div class="slider" data-mozert='{"parallax":true,"speed":700}'>
  <div>
    <img src="a.jpg" data-parallax-x="-20%" alt="">
    <h2 data-parallax-x="-60%" data-parallax-opacity="0">Title</h2>
  </div>
</div>
<!-- Values are the offset when the slide is one position away. Add data-parallax-bg on an element inside the slider to move a background layer. -->

Zoom

Double-click or double-tap an img/canvas/video (or an element with class mozert-zoom-target) in the active slide. Pinch on touch screens, ctrl+wheel on desktop. While zoomed, dragging pans the image.

const s = new Mozert('.gallery', { zoom: { max: 3 } });
s.zoom.toggle(); s.zoom.in(); s.zoom.out(); s.zoom.reset();
s.on('zoomChange', (slider, scale) => {});

Virtual slides

const slider = new Mozert('#big', {
  virtual: {
    slides: myArrayOf10000Items,
    renderSlide: (item, i) => '<div class="card">' + item.title + '</div>',  // optional
    addSlidesBefore: 2, addSlidesAfter: 3,
    cache: false                       // false = unload slides that leave the window
  },
  slidesToShow: 3
});
slider.virtual.appendSlide(item);  slider.virtual.prependSlide(item);  slider.virtual.removeSlide(0);  slider.virtual.update();

Start with an empty container element; Mozert creates lightweight slide shells and fills only those near the viewport. Virtual mode disables infinite.

Lazy loading

<img data-lazy="photo.jpg" data-lazy-srcset="photo-2x.jpg 2x" alt="">
<div data-lazy-bg="hero.jpg"></div>
<!-- lazyLoad: 'ondemand' (default) loads when a slide is about to show; 'progressive' loads the rest after the first paint. -->

Events: lazyLoaded and lazyLoadError.

Arrows and dots

// Your own arrow markup
new Mozert('.slider', {
  prevArrow: '<button type="button" class="my-arrow">&larr; Prev</button>',
  nextArrow: '<button type="button" class="my-arrow">Next &rarr;</button>'
});

// Put the arrows and the dots in a control bar anywhere on the page
// <div class="bar"><div id="arrows"></div><div id="dots"></div></div>
new Mozert('.slider', {
  appendArrows: '#arrows',   // selector or element
  appendDots: '#dots',
  dots: true
});

prevArrow and nextArrow take an HTML string or an element, so the arrows can look and read however you want. Mozert adds the classes mozert-prev / mozert-next and wires the clicks, the disabled state at the ends and the aria-label. appendArrows and appendDots move the arrows and the dots out of the slider into any element. The default round arrows are positioned over the slider, so when you append them elsewhere give them your own style (for example position: static). The dots keep working with customPaging, dotsClass and dots: 'dynamic' style pagination. See the live example on the Examples page.

Center padding

new Mozert('.slider', {
  centerMode: true,
  centerPadding: '140px',   // peek width on each side: px or %
  slidesToShow: 1,
  responsive: [{ breakpoint: 640, settings: { centerPadding: '36px' } }]
});

In centerMode the active slide stays in the middle and centerPadding sets how much of the neighbours you see on each side. Use pixels or a percentage, and shrink it on phones with responsive. It works with infinite, arrows, dots and the effects that centre the active slide.

Right to left (rtl)

new Mozert('.slider', {
  rtl: true,
  slidesToShow: 2.2,
  dots: true
});

rtl: true is for right-to-left pages. The slides start from the right, swiping, the previous/next arrows and the keyboard arrow keys follow the reading direction, and the slider gets dir="rtl" so your text and layout flip with it. It works with vertical off, with infinite, centerMode, thumbs and every pagination type. See the live example on the Examples page.

Thumbnails

// One option: a strip is created below the slider
new Mozert('#gallery', { thumbs: true });

// Your own strip (left empty it is filled for you; filled by you it is used as is)
new Mozert('#gallery', { thumbs: '#nav' });
new Mozert('#gallery', { thumbs: { el: '#nav', count: 4, options: { spaceBetween: 6 } } });

// Vertical gallery: main picture on the left, thumbnails stacked on the right
new Mozert('#gallery', { thumbs: { position: 'right', count: 4 } });
// position: 'left' | 'right' | 'top' | 'bottom' (default)

Thumbnails come from data-thumb on the slide, then the first <img>, then the slide's background. Clicking a thumbnail opens that slide, and changing slides highlights the matching thumbnail, even when the strip has nothing to scroll.

Magnifier

// Product gallery: thumbnails on the left, hover zoom on the picture
new Mozert('#product', {
  thumbs: { position: 'left', count: 4 },
  magnifier: true            // or { zoom: 2.4, button: true, active: false }
});

<img src="shoe-800.jpg" data-zoom="shoe-2400.jpg" alt="Shoe">   <!-- optional sharper file -->

slider.magnifier.enable();  slider.magnifier.disable();  slider.magnifier.toggle();  slider.magnifier.isOn();

A small magnifier button sits in the top right corner of the picture. When it is on, moving the mouse over a slide enlarges it around the pointer, like a product page in a shop. It is for mouse users only; touch screens keep normal swiping, and dragging the slider turns the zoom off while you hold the button. Set button: false to hide the button and control it with the API instead. Event: magnifier.

Scroll-driven

new Mozert('#story', {
  scrollDriven: {
    fill: true,     // the pinned slider takes the whole screen height: no empty space above or below
    offset: 76,     // px kept free at the top for a sticky header
    bottom: 24,     // px kept free at the bottom
    // top: 'center' // without fill: pin in the middle of the screen (or a number of px from the top)
    speed: 1.6      // px the slides travel per px of scroll: higher = shorter section, less empty space
  },
  infinite: false, arrows: false, dots: false, draggable: false
});

The slider is wrapped in a tall section and sticks while you scroll through it. The section is only as tall as the slides need to travel divided by speed; use step (px of scrolling per slide) if you want a fixed distance instead. To avoid empty space above and below, make the slider as tall as the screen under your header, for example .story .slide { height: calc(100svh - 96px) } with top: 76 (the header height plus a small gap). Needs a horizontal, non-looping slider, and no ancestor with overflow: hidden (that breaks position: sticky).

Synced sliders

new Mozert('#main',  { arrows: false, asNavFor: '#thumbs' });
new Mozert('#thumbs', { slidesToShow: 5, asNavFor: '#main', focusOnSelect: true });

Accessibility

  • Container gets role="region" and aria-roledescription="carousel"; slides get role="group" with "n of total" labels; clones are hidden from assistive tech.
  • Left/right (up/down when vertical) keys work when the slider has focus; globalKeyboard extends this to the whole page.
  • Autoplay pauses on hover and focus, and the live region switches to polite when autoplay is off or paused.
  • Users with prefers-reduced-motion: reduce get no autoplay and instant transitions (disable with respectReducedMotion: false).
  • Translate all strings with the labels option.

Theming

.my-slider {
  --mozert-accent: #3633f5;
  --mozert-arrow-bg: #fff;
  --mozert-arrow-fg: #111;
  --mozert-arrow-size: 44px;
  --mozert-dot-color: #bbb;
  --mozert-dot-active: #3633f5;
  --mozert-dot-size: 10px;
}

mozert-theme.css is optional: it only styles arrows and dots. Core layout lives in mozert.css.