An open API service indexing awesome lists of open source software.

https://github.com/matfantinel/carousel-pilot

A zero-dependency, framework-agnostic web component that enhances your existing scrollable content with carousel functionality.
https://github.com/matfantinel/carousel-pilot

carousel css scroll-snap slider

Last synced: 17 days ago
JSON representation

A zero-dependency, framework-agnostic web component that enhances your existing scrollable content with carousel functionality.

Awesome Lists containing this project

README

          

# 🎠 Carousel Pilot

[![npm version](https://badge.fury.io/js/carousel-pilot.svg)](//npmjs.com/package/carousel-pilot)

A zero-dependency, framework-agnostic web component that enhances your existing scrollable content with carousel functionality. The Carousel is yours, but Carousel Pilot handles navigation (prev/next), active state, autoplay, infinite loop and scroll tracking.

## Why?

Carousels are hard. You either use a heavy JS-based library or you gotta build things on your own. [CSS scroll snapping](https://fantinel.dev/blog/css-scroll-snapping/) has made it easier to build lightweight carousels, but some functionality like having the slides loop around are still heavily dependent on JS, and notably a pain to implement.

With Carousel Pilot you can have the both of best worlds: the scrolling and snapping is still handled by your CSS, responsive and reliable, but, [if JavaScript is available](https://www.kryogenix.org/code/browser/everyonehasjs.html), you can have Carousel Pilot jump in and add the extra goodies it provides, including a smooth infinite loop experience.

The cost? **17.7kB** (gzipped). It's not the most lightweight option out there, but hopefully it's the most straightforward one to use.

## How it works

Carousel Pilot is a [custom element](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements) (``) that wraps your existing scrollable track. It doesn't impose any layout or styles — you style the track and slides however you want (flexbox, CSS scroll snap, etc.) and Carousel Pilot wires up the behavior.

It is built with [Svelte 5](https://svelte.dev/), but works with any framework or no framework at all.

## Installation

```bash
npm install carousel-pilot
```

## Usage

### With a bundler (Vite, Webpack, Rollup, etc.)

Import once anywhere in your app — this registers the custom element globally:

```js
import 'carousel-pilot';
```

### In a Svelte project

```js
import 'carousel-pilot';
// or, to use the Svelte component directly:
import { CarouselPilot } from 'carousel-pilot';
```

### Via CDN / plain HTML

```html

```

## Basic example

The only required piece is a scrollable track element marked with `data-carousel-track`. Everything else is optional.

```html


  • Slide 1

  • Slide 2

  • Slide 3


Prev
Slide 1 of 3
Next

```

You are responsible for the track's CSS layout. A typical setup with CSS scroll snap:

```css
[data-carousel-track] {
display: flex;
gap: 1rem;
overflow: auto;
scroll-snap-type: x mandatory;
}

[data-carousel-track] > li {
flex: 0 0 300px;
scroll-snap-align: start;
}
```

## Slot conventions

Mark elements inside `` with these data attributes to connect them:

| Attribute | Role |
|---|---|
| `data-carousel-track` | The scrollable slide container (required) |
| `data-carousel-prev` | Button to scroll to the previous slide |
| `data-carousel-next` | Button to scroll to the next slide |
| `data-carousel-indicator` | Repeated indicator elements (e.g. dots); the active one gets an `active` class |
| `data-carousel-currentIndex` | Element whose text content is updated with the current slide number (1-based) |

## Props

### Selectors

These props accept a CSS selector string. Each one falls back to its corresponding `data-*` attribute if left empty.

| Prop | Default fallback | Description |
|---|---|---|
| `track` | `[data-carousel-track]` | The scrollable slide container. Required. |
| `prev` | `[data-carousel-prev]` | Button to scroll to the previous slide. |
| `next` | `[data-carousel-next]` | Button to scroll to the next slide. |
| `indicators` | `[data-carousel-indicator]` | Repeated indicator elements (e.g. dots). The active one receives an `active` class. |
| `current` | `[data-carousel-currentIndex]` | Element whose text content is set to the current slide number (1-based). |

### Behavior

| Prop | Type | Default | Description |
|---|---|---|---|
| `centered` | `boolean` | `false` | Centers the active slide in the track. Use `scroll-snap-align: center` on slides when enabled. |
| `scrollAmount` | `'slide' \| 'page'` | `'slide'` | How far prev/next scroll. `'slide'` uses the active slide's width; `'page'` uses the track's full width. |

### CSS injection

| Prop | Type | Default | Description |
|---|---|---|---|
| `addSpacers` | `boolean` | `true` | Injects invisible spacer elements so the first and last slides can be scrolled flush to the edge (or center when `centered` is on). |
| `showScrollShadow` | `boolean` | `false` | Injects a CSS scroll shadow on the track to hint that more content is scrollable. |
| `hideScrollbar` | `boolean` | `false` | Hides the track's scrollbar via injected CSS. |

### Autoplay

| Prop | Type | Default | Description |
|---|---|---|---|
| `autoplay` | `boolean` | `false` | Automatically advances slides on an interval. Pauses on hover, stops permanently on manual scroll or prev/next interaction. |
| `autoplayDelay` | `number` | `5000` | Interval in milliseconds between autoplay advances. |

### Loop

| Prop | Type | Default | Description |
|---|---|---|---|
| `loop` | `boolean` | `false` | Enables infinite looping by cloning slides on each side of the track. |
| `dedupeHeadings` | `boolean` | `true` | Replaces heading elements inside cloned slides with `

`s to prevent duplicate headings in the document outline. |
| `headingClasses` | `string` | `'h1, h2, h3, h4, h5, h6'` | Comma-separated class names applied to heading replacements in clones (index 0 → h1 class, 1 → h2, etc.). |

## JavaScript API

```js
const carousel = document.querySelector('carousel-pilot');

carousel.scrollToIndex(2); // scroll to a specific slide (0-based)
carousel.scrollNext(); // scroll forward one slide
carousel.scrollPrev(); // scroll backward one slide
```

## Events

```js
carousel.addEventListener('slide-change', (e) => {
console.log(e.detail.index); // 0-based index of the new active slide
console.log(e.detail.total); // total number of slides
});

carousel.addEventListener('autoplay-started', () => { /* ... */ });
carousel.addEventListener('autoplay-stopped', (e) => {
console.log(e.detail.paused); // true = paused (hovering), false = stopped permanently
});
```

## Development

The project uses [Storybook](https://storybook.js.org/) for local development. Example components live in `src/lib/examples/`.

```bash
npm install
npm run storybook
```

Storybook will start at **http://localhost:6006**.

## Building & publishing

Build both the Svelte library distribution and the standalone bundle:

```bash
npm run prepack
```

This runs `svelte-package` (for Svelte users) and a Vite library build (for everyone else), then validates the output with `publint`. Both outputs land in `dist/`.

Publish to npm:

```bash
npm publish
```

Make sure you've updated the `version` field in `package.json` before publishing.