Ilia Mashkov e273cad04b
CI / verify (push) Successful in 26s
CI / e2e (push) Successful in 26s
CI / verify (pull_request) Successful in 29s
CI / publish (push) Successful in 18s
CI / e2e (pull_request) Successful in 29s
CI / publish (pull_request) Has been skipped
feat: edge flags, overflow, and add/remove-aware observers
2026-07-02 11:26:45 +03:00
2026-07-02 10:19:44 +03:00
2026-07-01 10:42:01 +03:00

@ilia/carousel

Tiny, framework-agnostic scroll-snap carousel. Zero runtime deps. Native scroll handles touch/momentum, CSS handles snap + motion, JS is a thin layer.

  • core ≤1 KB gzip · dots ≤0.6 KB · autoplay ≤0.6 KB
  • Ships unminified ESM — your bundler minifies.

Install

This package lives on a private Gitea registry. Point the @ilia scope at it:

# .npmrc
@ilia:registry=https://git.allmy.work/api/packages/ilia/npm/
yarn add @ilia/carousel

Entry points

Import What
@ilia/carousel createCarousel(track) core
@ilia/carousel/dots dots() — Firefox/legacy dot fallback (self-gates)
@ilia/carousel/autoplay autoplay() — reduce-motion-aware auto-advance
@ilia/carousel/carousel.css snap track, native markers, opt-in .fx effect

Usage

<div class="track" id="carousel">
  <div class="slide"></div>
  <div class="slide"></div>
  <div class="slide"></div>
</div>
<button id="prev" aria-label="Previous"></button>
<button id="next" aria-label="Next"></button>
<!-- Firefox/legacy dot fallback; native ::scroll-marker owns dots elsewhere -->
<div id="dots" aria-label="Choose slide">
  <button aria-label="Slide 1"></button>
  <button aria-label="Slide 2"></button>
  <button aria-label="Slide 3"></button>
</div>
import { createCarousel } from '@ilia/carousel';
import { dots } from '@ilia/carousel/dots';
import { autoplay } from '@ilia/carousel/autoplay';
import '@ilia/carousel/carousel.css';

const track = document.getElementById('carousel');
const c = createCarousel(track);

// Arrows are just your own handlers — no module needed.
document.getElementById('next').onclick = () => c.next();
document.getElementById('prev').onclick = () => c.prev();

// Dots: no-ops where native ::scroll-marker exists (no double dots).
dots(c, document.getElementById('dots'));

// Opt-in auto-advance. Provide a visible pause control (see a11y note).
const stop = autoplay(c, { interval: 4000, root: track });

Add the opt-in scroll-driven effect with class="track fx" — it degrades to plain snap where animation-timeline: view() is unsupported.

Accessibility

  • autoplay() never starts under prefers-reduced-motion: reduce, and the .fx effect + smooth scrolling are gated behind @media (prefers-reduced-motion: no-preference).
  • If you use autoplay(), you must provide a visible pause/stop control (WCAG 2.2.2) — wire it to the returned stop().
  • Give dot buttons accessible labels (aria-label).

Browser support

Feature Chrome Safari Firefox
scroll-snap + core path
::scroll-marker native dots 135+ 18.2+ ⚠️ → JS dots() fallback
scroll-driven .fx ⚠️ partial → plain snap

Index tracking uses IntersectionObserver (universal today); a scrollsnapchange upgrade is deferred until Firefox ships it.

Release

npm version <patch|minor|major>
git push --follow-tags   # CI verifies, runs e2e, publishes on the v* tag
S
Description
No description provided
Readme
142 KiB
Languages
TypeScript 90.5%
CSS 6.2%
HTML 3.3%