@preline/carousel
v4.2.0
Published
Preline UI is an open-source set of prebuilt UI components based on the utility-first Tailwind CSS framework.
Readme
Carousel
Build carousels and sliders with Carousel JavaScript plugin.
Contents
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.
npm i @preline/carouselCSS
Use @source to register the plugin's JavaScript path for Tailwind CSS scanning, then @import the plugin's CSS files into your Tailwind CSS file.
@import "tailwindcss";
/* @preline/carousel */
@source "../node_modules/@preline/carousel/*.js";
@import "./node_modules/@preline/carousel/variants.css";
@import "./node_modules/@preline/carousel/theme.css";JavaScript
Include the JavaScript that powers the interactive elements near the end of your </body> tag:
<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.
<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.
@preline/carousel is the auto-init entry: it scans the DOM and initializes matching elements automatically.
import "@preline/carousel";@preline/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.
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 @types/ 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.
<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 optionshs-carousel: Required wrapper for slides collection, must containoverflow-hiddenclasshs-carousel-body: Required slides containerhs-carousel-slide: Required for each slide elemenths-carousel-prev: Optional previous slide buttonhs-carousel-next: Optional next slide buttonhs-carousel-pagination: Optional pagination container
Initial State:
- Carousel body typically starts with
opacity-0which 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:
<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)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)
// 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)
// 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
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
// 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.
<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.
<div data-hs-carousel='{
"isAutoPlay": true,
"speed": 5000,
"isInfiniteLoop": true
}'>
<!-- Carousel content -->
</div>Pattern 3: Programmatic Control
Control carousel from external buttons.
<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.
