preline
Version:
Preline UI is an open-source set of prebuilt UI components based on the utility-first Tailwind CSS framework.
391 lines (295 loc) • 15.2 kB
Markdown
# Carousel
Build carousels and sliders with Carousel JavaScript plugin.
[](https://www.npmjs.com/package/@preline/carousel) [](https://opensource.org/licenses/MIT) [](https://preline.co/plugins/carousel.html)
## Contents
- [Overview](#overview)
- [Installation](#installation)
- [Basic usage](#basic-usage)
- [Configuration Options](#configuration-options)
- [JavaScript API](#javascript-api)
- [Events](#events)
- [Common Patterns](#common-patterns)
- [License](#license)
## Overview
The Carousel component provides a flexible, feature-rich slider for displaying multiple items in a scrollable container. It supports autoplay, infinite loop, drag gestures, responsive breakpoints, and multiple display modes.
**Key Features:**
- Multiple slides in a scrollable container
- Autoplay and infinite loop support
- Drag/swipe gestures for navigation
- Responsive breakpoints for different screen sizes
- Multiple display modes (default, snap, bounded)
- Programmatic control via JavaScript API
- Keyboard navigation support
- Customizable pagination dots
## Installation
To get started, install Carousel plugin via npm, else you can skip this step if you are already using Preline UI as a package.
```bash
npm i /carousel
```
### CSS
Use [``](https://tailwindcss.com/docs/functions-and-directives#source-directive) to register the plugin's JavaScript path for Tailwind CSS scanning, then [`@import`](https://tailwindcss.com/docs/functions-and-directives#import-directive) the plugin's CSS files into your Tailwind CSS file.
```css
"tailwindcss";
/* @preline/carousel */
"../node_modules/@preline/carousel/*.js";
"./node_modules/@preline/carousel/variants.css";
"./node_modules/@preline/carousel/theme.css";
```
### JavaScript
Include the JavaScript that powers the interactive elements near the end of your `</body>` tag:
```html
<script src="./node_modules/@preline/carousel/index.js"></script>
```
### Manual Initialization
Use the `non-auto` entry if you need manual initialization. In this mode, automatic initialization on page load is not included, so the component should be initialized explicitly.
```html
<script type="module">
import HSCarousel from "@preline/carousel/non-auto.mjs";
new HSCarousel(document.querySelector("#carousel"));
</script>
```
### Via Bundler
When using a bundler (Vite, webpack, etc.), import the plugin directly as an ES module.
`/carousel` is the auto-init entry: it scans the DOM and initializes matching elements automatically.
```js
import "@preline/carousel";
```
`/carousel/non-auto` is the manual entry: use it when you want explicit control over when initialization happens, either via `autoInit()` or by creating a specific instance yourself.
```js
import HSCarousel from "@preline/carousel/non-auto";
HSCarousel.autoInit();
// Or initialize a specific element manually
const el = document.querySelector("#carousel");
if (el) new HSCarousel(el);
```
### TypeScript
This package ships with TypeScript type definitions. No additional `/` package is needed.
## Basic usage
The following example demonstrates the minimal HTML structure required for a carousel component. This is a base template without custom styling - you can apply your own CSS classes and styles as needed. The carousel displays three slides with previous/next navigation buttons.
```html
<div data-hs-carousel='{
"loadingClasses": "opacity-0"
}' class="relative">
<div class="hs-carousel relative overflow-hidden w-full min-h-64">
<div class="hs-carousel-body absolute top-0 bottom-0 start-0 flex flex-nowrap transition-transform duration-700 opacity-0">
<div class="hs-carousel-slide">
1
</div>
<div class="hs-carousel-slide">
2
</div>
<div class="hs-carousel-slide">
3
</div>
</div>
</div>
<button type="button" class="hs-carousel-prev">
<span aria-hidden="true">«</span>
<span class="sr-only">Previous</span>
</button>
<button type="button" class="hs-carousel-next">
<span class="sr-only">Next</span>
<span aria-hidden="true">»</span>
</button>
</div>
```
**Structure Requirements:**
- `data-hs-carousel`: Required on the container element, contains configuration options
- `hs-carousel`: Required wrapper for slides collection, must contain `overflow-hidden` class
- `hs-carousel-body`: Required slides container
- `hs-carousel-slide`: Required for each slide element
- `hs-carousel-prev`: Optional previous slide button
- `hs-carousel-next`: Optional next slide button
- `hs-carousel-pagination`: Optional pagination container
**Initial State:**
- Carousel body typically starts with `opacity-0` which is removed after loading
- First slide is active by default (index 0)
## Configuration Options
### Data Options
Data options are specified in the `data-hs-carousel` attribute as a JSON object.
| Option | Type | Default | Description |
| --- | --- | --- | --- |
| `currentIndex` | number | `0` | Specifies the index of the current slide initially (from 0 to slides quantity). |
| `loadingClasses` | string | `"opacity-0"` | Specifies which classes should be removed after the carousel is loaded. CSS classes should be separated with space. |
| `dotsItemClasses` | string | - | Specifies which classes will be added to the point elements (which are generated automatically). CSS classes should be separated with space. |
| `isAutoHeight` | boolean | `false` | Sets the height of the carousel to the height of the current slide. |
| `isAutoPlay` | boolean | `false` | Enables autoplay. Slides advance automatically at the interval specified by `speed`. |
| `isInfiniteLoop` | boolean | `true` | Enables infinite loop. When reaching the last slide, it wraps to the first slide. |
| `isCentered` | boolean | `false` | Enables centered mode. This mode adds space on the sides to center the slides. |
| `isSnap` | boolean | `false` | Enables a mode in which you can scroll the contents of the slider using the scroll along the x-axis, while the active slider is centered relative to the slider. |
| `isScrollBlocked` | boolean | `false` | Prevents the user from scrolling the slider. Useful when you need to prevent scrolling while the carousel is active. |
| `isDraggable` | boolean | `false` | Adds the ability to change slides using dragging. Requires adding `hs-carousel:dragging:transition-none` class to the `hs-carousel-body`. Not working with `isSnap: true` option. |
| `isRTL` | boolean | `false` | Turns on RTL (right-to-left) mode. |
| `hasSnapSpacers` | boolean | `true` | Adds additional elements to create a constant centering effect. |
| `slidesQty` | object \| number | `1` | Allows to set the number of slides to display at a certain screen resolution if passed as an object (e.g., `{"xs": 1, "md": 2, "lg": 3}`). If passed as a number, the specified number of slides will be displayed for all screen resolutions. |
| `slideBy` | object \| number | `1` | Specifies how many slides to move when navigating through the carousel. Can be a number for all screen sizes or an object with breakpoint-specific values. |
| `speed` | number | `4000` | Autoplay animation speed in milliseconds. Available if `isAutoplay: true`. |
| `updateDelay` | number | `0` | Allows you to delay the update function when resizing a window. Suitable for a slider with images, for more accurate calculation of the size of the images. |
| `mode` | `"default"` \| `"snap"` \| `"bounded"` | `"default"` | Defines the carousel's behavior mode. `default` for standard sliding, `snap` for scroll-based navigation with snap points, and `bounded` for a fixed-width container with responsive slides. |
| `boundedOptions` | object | `null` | Configuration options for the bounded mode carousel. Includes `maxWidth` to set the maximum width of the carousel container, `slidesGap` to define spacing between slides, and `spacersWidth` to control the width of side spacers. When `spacersWidth` is set to `"auto"`, it automatically calculates equal spacing on both sides. |
**Example:**
```html
<div data-hs-carousel='{
"isAutoPlay": true,
"speed": 3000,
"slidesQty": {"xs": 1, "md": 2, "lg": 3},
"isInfiniteLoop": true
}'>
<!-- Carousel content -->
</div>
```
### Required CSS Classes
These classes define the structure and must be present for the carousel to function.
| Class | Required On | Purpose |
| --- | --- | --- |
| `hs-carousel` | Wrapper container | A wrapper for a collection of slides. Must contain the `overflow-hidden` class for correct functionality. |
| `hs-carousel-body` | Slides container | Container for all slide elements. |
| `hs-carousel-slide` | Each slide element | Identifies an individual slide. |
### Optional CSS Classes
| Class | Required On | Purpose |
| --- | --- | --- |
| `hs-carousel-prev` | Previous button | Previous slide navigation button. |
| `hs-carousel-next` | Next button | Next slide navigation button. |
| `hs-carousel-pagination` | Pagination container | Pagination container. If it doesn't contain nested elements, dots are generated automatically. If it contains elements with `hs-carousel-pagination-item` class, they will act as dots. |
### Tailwind Modifiers
| Name | Description |
| --- | --- |
| `hs-carousel-active:*` | A modifier that allows you to set Tailwind classes when the active slide was shown. |
| `hs-carousel-disabled:*` | A modifier that allows you to set Tailwind classes for arrow buttons when they are `disabled`. |
| `hs-carousel:dragging:*` | A modifier that allows you to set Tailwind classes for `hs-carousel-body` when dragging. |
## JavaScript API
The `HSCarousel` object is available in the global `window` object after the plugin is loaded.
### Instance Methods
These methods are called on a carousel instance.
| Method | Parameters | Return Type | Description |
| --- | --- | --- | --- |
| `goToPrev()` | None | `void` | Navigates to the previous slide. |
| `goToNext()` | None | `void` | Navigates to the next slide. |
| `goTo(index)` | `index`: `number` | `void` | Navigates to the slide at the specified index. Index starts from 0. |
| `recalculateWidth()` | None | `void` | Recalculates the width of the carousel. Useful after dynamically adding or removing slides, or when window is resized. |
| `destroy()` | None | `void` | Destroys the carousel instance, removes all generated markup, classes, and event listeners. Use when removing carousel from DOM. |
### Static Methods
These methods are called directly on the `HSCarousel` class.
| Method | Parameters | Return Type | Description |
| --- | --- | --- | --- |
| `HSCarousel.getInstance(target, isInstance)` | `target`: `HTMLElement \| string` (CSS selector)<br>`isInstance`: `boolean` (optional) | `HSCarousel \| { id: string \| number, element: HSCarousel } \| null` | Returns the carousel instance associated with the target. If `isInstance` is `true`, returns collection item object `{ id, element }` where `element` is the `HSCarousel` instance. If `isInstance` is `false` or omitted, returns the `HSCarousel` instance directly. Returns `null` if carousel instance is not found. |
### Usage Examples
**Example 1: Using instance methods (public API)**
```javascript
// Create a new carousel instance
const carousel = new HSCarousel(document.querySelector('#hs-carousel'));
const goToSecondBtn = document.querySelector('#hs-go-to-second-btn');
// Navigate to slide by index
goToSecondBtn.addEventListener('click', () => {
carousel.goTo(1); // Go to second slide (index 1)
});
```
**Example 2: Getting instance and using methods (recommended pattern)**
```javascript
// Get the carousel instance
const instance = HSCarousel.getInstance('#hs-carousel', true);
if (instance) {
const { element } = instance; // element is the HSCarousel instance
const goToSecondBtn = document.querySelector('#hs-go-to-second-btn');
const prevBtn = document.querySelector('#hs-prev-btn');
const nextBtn = document.querySelector('#hs-next-btn');
// Navigate to specific slide
goToSecondBtn.addEventListener('click', () => {
element.goTo(1);
});
// Navigate to previous slide
prevBtn.addEventListener('click', () => {
element.goToPrev();
});
// Navigate to next slide
nextBtn.addEventListener('click', () => {
element.goToNext();
});
// Recalculate width after dynamic changes
function updateCarousel() {
element.recalculateWidth();
}
// Clean up when removing from DOM
function removeCarousel() {
element.destroy();
}
}
```
**Example 3: Destroying carousel instance**
```javascript
const instance = HSCarousel.getInstance('#hs-carousel', true);
if (instance) {
const { element } = instance;
const removeBtn = document.querySelector('#hs-remove-btn');
removeBtn.addEventListener('click', () => {
// Clean up before removing from DOM
element.destroy();
// Now safe to remove the element
document.querySelector('#hs-carousel').remove();
});
}
```
## Events
Carousel instances emit events that can be listened to for slide lifecycle hooks.
| Event Name | When Fired | Callback Parameter | Description |
| --- | --- | --- | --- |
| `on:update` | After the active slide changes | `number` (zero-based index of the current slide) | Fires after navigating to the next or previous slide, or after `goTo()` is called. |
### Event Usage Example
```javascript
// Get carousel instance
const instance = HSCarousel.getInstance('#hs-carousel', true);
if (instance) {
const { element } = instance;
// Listen for slide changes
element.on('update', (currentIndex) => {
console.log('Active slide:', currentIndex);
// Update external indicators, counters, etc.
});
}
```
## Common Patterns
### Pattern 1: Responsive Carousel
Display different number of slides at different breakpoints.
```html
<div data-hs-carousel='{
"slidesQty": {"xs": 1, "sm": 2, "md": 3, "lg": 4}
}'>
<!-- Carousel content -->
</div>
```
### Pattern 2: Autoplay Carousel
Automatically advance slides at regular intervals.
```html
<div data-hs-carousel='{
"isAutoPlay": true,
"speed": 5000,
"isInfiniteLoop": true
}'>
<!-- Carousel content -->
</div>
```
### Pattern 3: Programmatic Control
Control carousel from external buttons.
```html
<div id="hs-carousel-first" data-hs-carousel>
<!-- Carousel content -->
</div>
<button id="hs-go-to-first">Go to First</button>
<button id="hs-go-to-last">Go to Last</button>
<script>
const instance = HSCarousel.getInstance('#hs-carousel-first', true);
if (instance) {
const { element } = instance;
document.querySelector('#hs-go-to-first').addEventListener('click', () => {
element.goTo(0);
});
document.querySelector('#hs-go-to-last').addEventListener('click', () => {
// Assuming 5 slides (indices 0-4)
element.goTo(4);
});
}
</script>
```
## License
Copyright (c) 2026 Preline Labs.
Licensed under the [MIT License](https://opensource.org/licenses/MIT).