A lightweight dependency-free css carousel. CSS can scroll, why not use it?
Integrating CarouCSSel with native CSS scroll techniques, including CSS Scroll-driven Animations, is essentially writing CSS. Acting as a wrapper around CSS scrolling, CarouCSSel simplifies the process, even in complex layouts, by providing controls such as buttons or paginations (see Features section). With CarouCSSel, you can effortlessly create dynamic and visually engaging carousels that respond smoothly to user interactions and scrolling events.
- Take a quick tour
- Try the examples
- Read the docs
- Installation
- Usage
- Features
- Options
- Properties
- Methods
- SCSS Mixins
- Build a custom feature
- Polyfills
- License
CarouCSSel is available on NPM:
npm install caroucssel --save
or
yarn add caroucssel
or in the browser
<link rel="stylesheet" href="https://unpkg.com/caroucssel@latest/styles/caroucssel.min.css" />
<script src="https://unpkg.com/caroucssel@latest"></script>
The carousel is based on two elements. The most important part is the styling. CarouCSSel is shipped with a prebuild CSS-file (for basic usage) and an SCSS-file which contains mixins to set up the carousel. On the other hand, there is a JavaScript class which enhances the carousel by adding controls.
The prebuild CSS-file only contains selectors for basic usage. It's recommended to use the SCSS-mixins for better customizability. The CSS comes with two class selectors. .caroucssel
creates a scrolling area where the child elements are horizontally arranged. The second, optional .use-snap
enables basic scroll-snap support at 100% size, aligned to the left.
<link rel="stylesheet" href="caroucssel.min.css">
<div class="caroucssel use-snap">
<div class="item">Item 1</div>
<div class="item">Item 2</div>
<div class="item">Item 3</div>
</div>
The SCSS gives the freedom to choose your own selectors, which should have a carousel feature. It also allows you to easily customize the behavior depending on media queries.
@import '~caroucssel';
.my-carousel {
@include caroucssel();
@include caroucssel-snap($at: 100%);
@media screen and (min-width: 700px) {
@include caroucssel-snap($at: 50%);
}
}
Some browsers show a horizontal scrollbar depending on operating system or settings of the operating system. The JavaScripts detects that appearance and attaches some styles to hide them (See Mask feature). On top of that, any other features like buttons or pagination can added as an option. A basic instance of CarouCSSel is created as followed:
import {Carousel} from 'caroucssel';
const el = document.querySelector('.carousel');
const carousel = new Carousel(el, { /* options here */ });
CarouCSSel provides a plugin mechanism called "features". Each behavior can be added with a custom feature implementation that is passed as a features
list into an instance of the carousel. CarouCSSel comes with a set of predefined features like Buttons and Pagination. All features are tree-shakeable to keep your bundle as small as possible.
Buttons allow the user to scroll step by step, forwards and backward between items inside the carousel. Buttons are rendered as <button>
into the DOM as a direct sibling of the carousel element. By default, the buttons are rendered with required WIA-ARIA attributes. To enable buttons, pass an instance of the feature to the features
list:
import {Carousel} from 'caroucssel';
import {Buttons} from 'caroucssel/features/buttons';
const el = document.querySelector('.carousel');
const carousel = new Carousel(el, {
features: [
new Buttons(),
],
});
Buttons are customizable by additional options. The following options are available:
className
– a string which represents the base class name of both buttons (see other options to change class name for "previous" and "next" button separately) – Default value is:'button'
.nextClassName
– a string of a class name used to identify this button – Default value is:'is-next'
nextLabel
– a string of the label for this button – Default value is:'Next'
nextTitle
– a string of the title for this button – Default value is:'Go to next'
previousClassName
– a string of a class name used to identify this button – Default value is:'is-previous'
previousLabel
– a string of the label for this button – Default value is:'Previous'
previousTitle
– a string of the title for this button – Default value is:'Go to previous'
template
– is a function which returns a HTML-string for each button. A context object is passed, containing information about:className
– a string of class names for the current buttoncontrols
– a string reference to the HTML id of the carousel element. this is relevant for anaria-controls="..."
attribute.label
– a string of the button label defined bynextLabel
andpreviousLabel
title
– a string of the button title defined bynextTitle
andpreviousTitle
A full set of button options could look like this:
import {Carousel} from 'caroucssel';
import {Buttons} from 'caroucssel/features/buttons';
const el = document.querySelector('.carousel');
const carousel = new Carousel(el, {
features: [
new Buttons({
className: 'my-button',
nextClassName: 'my-next-button',
nextTitle: 'Click this button to go one step forward',
nextLabel: '>'
previousClassName: 'my-previous-button',
previousTitle: 'Click this button to go one step back',
previousLabel: '<'
template: ({className, label, title}) =>
`<button class="${className}" title="${title}">
${label}
</button>`,
}),
],
});
The Pagination (or dots) is a list of buttons that allow navigating directly to a specific item/index inside the carousel. By default, the pagination is rendered with required WIA-ARIA attributes. To enable the pagination, pass an instance of the feature to the features
list:
import {Carousel} from 'caroucssel';
import {Pagination} from 'caroucssel/features/pagination';
const el = document.querySelector('.carousel');
const carousel = new Carousel(el, {
features: [
new Pagination(),
],
});
The pagination can be customized by additional options. The following options are available:
className
– a string which represents the class name for the<ul>
element of the pagination – Default value is:'pagination'
label
– a function which returns a string for the label of each button inside the pagination. A data object is passed as param into the invoked function, containing information about:index
– a number of the current item indexpages
– all existing pages, a list of grouped indexespage
– the current page
title
– a function which returns a string for the title of each button inside the pagination. A data object is passed as param into the invoked function, containing information about:index
– a number of the current item indexpages
– all existing pages, a list of grouped indexespage
– the current page
template
– is a function which returns an HTML-string of the complete pagination. The default implementation invokes thelabel
andtitle
functions to create the string. A data object is passed as param into the invoked function, containing information about:className
– a string with the value of theclassName
option.controls
– a string reference to the HTML id of the carousel element. this is relevant for anaria-controls="..."
attribute.pages
– all existing pages, a list of grouped indexeslabel
– the function reference forlabel
to create a button labeltitle
– the function reference fortitle
to create a button title
A full set of pagination options could look like this:
import {Carousel} from 'caroucssel';
import {Pagination} from 'caroucssel/features/pagination';
const el = document.querySelector('.carousel');
const carousel = new Carousel(el, {
features: [
new Pagination({
className: 'my-pagination',
label: ({index}) => `${index + 1}.`,
title: ({index}) => `Jump to ${index + 1}. item`,
template: ({className, pages, label, title}) =>
`<div class="${className}">
${pages.map((page, index) =>
`<button title="${title({index})}">${label({index})}</button>`
).join('')}
</div>`
}),
],
});
There is a Mask feature that is used by the Carousel instance by default. In most cases, there is no need to import and apply this feature directly. It's used to calculate and hide the scrollbars. If you would like to opt out of this feature, you need to set the enabled
option to false
.
import {Carousel, Mask} from 'caroucssel';
const el = document.querySelector('.carousel');
const carousel = new Carousel(el, {
features: [
new Mask({
enabled: false,
}),
],
});
This feature will wrap an element (mask) around the passed element that contains the scrollable items. This mask is used to hide the scrollbar. It is a div
element that has a default class name caroucssel-mask
. To change this class name or the tag, use the options className
and tagName
:
import {Carousel, Mask} from 'caroucssel';
const el = document.querySelector('.carousel');
const carousel = new Carousel(el, {
features: [
new Mask({
className: `my-mask`,
tagName: `section`,
}),
],
});
This will add mouse controls to the carousel by enabling drag and drop scrolling using the mouse.
import {Carousel} from 'caroucssel';
import {Mouse} from 'caroucssel/features/mouse';
const el = document.querySelector('.carousel');
const carousel = new Carousel(el, {
features: [
new Mouse(),
],
});
The bahvior can be customized by additional options. The following options are available:
indicator
– a boolean to enable a mouse cursor to visualize that the user can drag the items.onStart
– a function that is called when the user stats to drag.onDrag
– a function that is called when the user is dragging.onEnd
– a function that is called when the user stops to drag.
Set the initial scroll index. The option format as an array follows API format for possibly multiple visible items (read more). To set an index you need to pass an array with at least one element. When passing more than one, the rest will be ignored.
const carousel = new Carousel(el, {
index: [42],
});
The carousel will ignore "invisible" html elements as scroll items by default. These elements are: <link>
, <meta>
, <noscript>
, <script>
, <style>
and <title>
. Other elements with a hidden
attribute are ignored as well: <div hidden>Hidden item</div>
.
filterItem
allows to manually filter elements as items. This function is a regular filter function which receives the current element (and it's index as child element) and returns a boolean that flags if the element is a valid item.
const carousel = new Carousel(el, {
filterItem: (item, index) => (index % 3 === 0),
});
onScroll
a function which is invoked when the user scrolls through the carousel. An object containing the currentindex
(a list of visible indexes), an eventtype
, a reference to the carousel instance (target
) and the original scroll event (originalEvent
) is passed to the function.
The current scroll-behavior of the carousel. It refers to the css property scroll-behavior using the values auto
and smooth
. The default value is smooth
.
Returns and/or sets the current index of the carousel. The returned index is a list (array) of indexes that are currently visible (depending on each item width). To set an index you need to pass an array with at least one element. When passing more than one, the rest will be ignored.
Returns an array of all child dom elements of the carousel.
Returns an array of all pages. Each page is a group of indexes that matches a page.
Returns the index of the current page.
Returns the id-attribute value of the carousel.
Returns the dom element reference of the carousel which was passed into the constructor.
Returns the dom element reference of the mask element that wraps the carousel element. If the mask is not enabled, the return value is null
.
Enforces an update of all enabled features of the carousel. This is, for example, useful when changing the number of items inside the carousel.
This completely deconstructs the carousel and applied features and returns the dom to its initial state.
Adds the minimal set of styles required to display the carousel.
Enables CSS-snapping inside the carousel. The following parameters are available:
$at
– defines the snap point length. – Default value is:100%
A feature is a plugin that implements all required functions and properties to match a specified API. If you're writing a feature in typescript, you can implement the interface IFeature
. If you're using plain javascript, follow the typedocs as guideline.
export class CustomFeature {
get name() {
// Return your unique feature name here. Prevent to use a too generic name here.
// You could use a combination of your github and repo name for example.
return 'github-username:custom-feature';
}
init(carousel) {
// This function will be called when the carousel initializes all features.
// An (proxied) instance of the carousel will be passed as parameter. Store
// this reference to access it later on for your feature implementation....
this.carousel = carousel;
// Initialize your feature...
this.doSomething();
}
update(event) {
// This function will be called when the carousel fires an internal update.
// The passed event object contains a reason (event.type) to describe
// why this was triggered:
//
// * 'scroll' (the carousel scrolled)
// * 'resize' (the carousel resized)
// * 'forced' (the carousel.update() function was called from external code)
// * 'feature' (the carousel.update() function was called from an other feature)
console.log(event.type);
// React on the update: take care of the event.type, maybe a partial
// update is already enough...
this.doSomething();
}
destroy() {
// This function will be called when the carousel is destroyed. Ensure
// to fully detach all instances and event listeners. Also, roll back all
// changes to the DOM to restore the initial state...
this.carousel = null;
}
doSomething() {
// This is just an example function. Implement the feature the way you want...
// If you need to trigger an update to the caroucel and attached other
// features, call the update() function of the carousel and pass your
// feature - Only do this if it's needed to update any of the instances!
this.carousel.update(this);
}
}
then use it...
import {Carousel} from 'caroucssel';
import {CustomFeature} from './features';
const el = document.querySelector('.carousel');
const carousel = new Carousel(el, {
features: [
new CustomFeature(),
],
});
CarouCSSel is using scroll-behavior: 'smooth'
which is supported in most modern browsers. For non-supporting browsers, there is a polyfill by Dustan Kasten.