Skip to content

Shelamkoff/carousel

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

@shelamkoff/carousel

npm version Live demo MIT license

Framework-agnostic, position-based carousel and slider with responsive layouts, loop mode, cancellable transitions, typed events, touch gestures, accessibility, and composable plugins. Published as an ESM package for modern browsers.

Live demo · npm · Русская версия

Highlights

  • Responsive single- and multi-slide layouts with fixed or automatic scroll steps.
  • Loop mode, cancellable transitions, keyboard control, touch and mouse gestures.
  • Arrows, dots, thumbnails, autoplay, lazy loading, swipe, and parallax plugins.
  • Framework-independent lifecycle, typed events, and TypeScript declarations.

Installation

npm install @shelamkoff/carousel @shelamkoff/event-bus

Import the required stylesheet once in the application:

import '@shelamkoff/carousel/styles.css'

carouselStylesUrl is also exported when the host needs to create its own <link> element.

Quick start

<div id="gallery"></div>
import {
  Carousel,
  createArrows,
  createDots,
  createKeyboard,
  createSwipe,
} from '@shelamkoff/carousel'
import '@shelamkoff/carousel/styles.css'

const carousel = new Carousel('#gallery', [
  {
    content: () => Object.assign(document.createElement('img'), {
      src: '/photos/forest.jpg',
      alt: 'Forest',
    }),
    thumb: '/photos/forest-thumb.jpg',
  },
  { content: '<p>Trusted application markup</p>' },
], {
  loop: true,
  gap: 16,
  plugins: [
    createArrows(),
    createDots(),
    createKeyboard(),
    createSwipe({ mouse: true }),
  ],
})

const unsubscribe = carousel.on('slide:change', ({ index, slide }) => {
  console.log(index, slide.meta)
})

carousel.next()

// Later:
unsubscribe()
carousel.destroy()

The container may be an HTMLElement or a CSS selector. A selector that does not resolve to an element causes the constructor to throw.

Slide data

interface SlideData {
  content: string | HTMLElement | (() => HTMLElement)
  thumb?: string
  lazy?: boolean
  meta?: Record<string, unknown>
}
  • A render function is the safest choice for dynamic or untrusted data.
  • An HTMLElement is moved into the carousel; it is not cloned.
  • A string is assigned as HTML and is therefore trusted developer input.
  • thumb is consumed by the thumbnails plugin, lazy by lazy loading, and meta remains application-owned metadata.

Configuration

Option Type Default Purpose
slidesPerView number 1 Number of visible slides. Positive values are required.
slidesPerScroll number | 'auto' 1 Navigation step. 'auto' uses the resolved visible count.
gap number 0 Gap between slides in CSS pixels.
transition 'slide' | 'fade' 'slide' Movement strategy. Fade mode displays one slide at a time.
transitionDuration number 400 Transition duration in milliseconds.
loop boolean false Enables circular navigation using loop clones.
startIndex number 0 Initial logical slide index. Used only during construction.
breakpoints Record<number, Partial<CarouselResponsiveOptions>> none Options applied when the viewport is at least the numeric width.
plugins CarouselPlugin[] [] Plugins installed during construction.

Breakpoint values override base options. The carousel preserves the current logical slide, cancels obsolete animation work, and rebuilds layout when the active breakpoint changes.

const carousel = new Carousel('#gallery', slides, {
  slidesPerView: 1,
  slidesPerScroll: 'auto',
  breakpoints: {
    640: { slidesPerView: 2, gap: 12 },
    1024: { slidesPerView: 4, gap: 20 },
  },
})

Public API

Method Result Description
use(plugin) this Installs a plugin. Plugin names must be unique.
getPlugin(name) plugin or undefined Returns the installed public plugin object.
next() / prev() void Moves by the resolved scroll step.
goTo(index) void Navigates to a logical slide index.
getIndex() number Current internal/render index. Prefer getRealIndex() in loop mode.
getRealIndex() number Current logical index in the source slide array.
getSlide(index?) slide or null Returns a logical slide; omitting the index returns the current slide.
getSlides() SlideData[] Returns a defensive array copy of slides.
addSlide(slide, index?) void Adds a slide and rebuilds the layout.
removeSlide(index) void Removes a logical slide and keeps the remaining index valid.
update(options) void Updates layout and behavior. plugins and startIndex are intentionally rejected.
on(event, handler) unsubscribe function Subscribes to an event.
off(event, handler) void Removes the exact handler.
once(event, handler) unsubscribe function Subscribes for one emission.
destroy() void Cancels animations, destroys plugins, removes generated DOM and listeners.

Do not call methods after destroy(). Create a new instance if the host needs to mount the carousel again.

Events

Event Payload
slide:beforeChange { fromIndex, toIndex }
slide:change { index, prevIndex, slide }
transition:start { fromIndex, toIndex }
transition:end { index }
resize { slidesPerView }
autoplay:start / autoplay:stop no payload
slide:lazyload { index, element }
slide:error { index, error }
destroy no payload

Rendering and lazy-load failures are isolated to the affected slide and reported through slide:error.

Built-in plugins

  • Arrows — previous and next buttons; edge hiding is enabled by default.
  • Dots — clickable pagination.
  • Thumbnails — bottom or side thumbnail navigation.
  • Keyboard — focus-scoped arrow keys by default; document-wide handling is opt-in.
  • Swipe — touch, pointer, resistance, and optional mouse drag.
  • Autoplay — interval playback with hover and interaction pausing.
  • Lazy load — observer-based image loading and configurable preloading.
  • Parallax — position-driven visual offset.

Install a plugin in plugins or with use() before destroying the carousel. A stateful plugin instance may belong to only one live carousel; create a fresh plugin object for every concurrent carousel.

Creating a plugin

A plugin has a unique name, install(context), and optional destroy():

export function createProgressPlugin() {
  let element = null

  return {
    name: 'progress',

    install(context) {
      element = document.createElement('output')
      element.className = 'carousel-progress'
      element.setAttribute('aria-live', 'polite')

      const render = () => {
        element.textContent = `${context.getRealIndex() + 1} / ${context.getSlideCount()}`
      }

      context.getRoot()?.append(element)
      context.on('slide:change', render)
      context.on('resize', render)
      render()
    },

    destroy() {
      element?.remove()
      element = null
    },
  }
}

The frozen context exposes owned event subscriptions, navigation commands, read-only state and resolved options, live DOM getters, position methods for gesture/effect plugins, and refreshLayout(). Context subscriptions are removed automatically. The plugin must still release its own DOM, global listeners, observers, timers, animation frames, object URLs, and third-party instances in destroy().

If install() throws, the carousel rolls back context subscriptions and invokes the plugin cleanup. Make destroy() safe after partial installation.

Security boundary

String slide.content and custom arrow HTML are inserted as HTML. They must contain trusted developer-controlled markup. For user-controlled content, build an element with textContent or sanitize the value before passing it to the carousel.

Demo

Open the live demo to try responsive layouts, loop and autoplay, fade, thumbnails, parallax, custom themes, and fixed scroll steps.

To run the same demo locally:

npm install
npm run demo

Open http://127.0.0.1:4173/demo.html.

Package exports

  • @shelamkoff/carousel — JavaScript API and TypeScript declarations.
  • @shelamkoff/carousel/styles.css — required carousel styles.
  • @shelamkoff/carousel/package.json — package metadata.

License

MIT.

About

Framework-agnostic JavaScript carousel and slider with responsive layouts, loop mode, touch gestures, animations, accessibility, and composable plugins.

Topics

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors