Odo Carousel
Performant, awesome carousels.
Support
IE9+ with polyfills.
To support IE<=11, you will need to add classList
and Element#closest
polyfills.
Dependencies
Odo Device, Odo Helpers, Odo Draggable, Tiny Emitter.
Odo Pointer, Draggable, and Carousel also expect Object.assign
from ES6 to be available.
Styles
This component has required css - css/odo-carousel.css. The theme (css/odo-carousel-theme.css) should also be included and customized to your design.
Regular
By default, carousels are draggable, have overflow, are horizontal, are not looped, are not slideshows, are not “jumped”, and do not have pagination. You can add slides, reset the carousel so it purges its cache of elements and finds the new ones, set the selected index, go previous or next slides, start a slideshow, pause a slideshow, and use the other public methods.
Markup
<h2 id="regular-title">Regular</h2>
<div id="regular" class="odo-carousel" aria-labelledby="regular-title">
<div class="odo-carousel__wrapper">
<ul class="odo-carousel__element">
<li class="odo-carousel__slide">1</li>
<li class="odo-carousel__slide">2</li>
<li class="odo-carousel__slide">3</li>
<li class="odo-carousel__slide">4</li>
</ul>
</div>
</div>
Setup
var regular = new OdoCarousel(document.getElementById('regular'));
Methods
You can also enable/disable the carousel by setting instance.isEnabled
.
// Some useful public methods.
goToPreviousSlide();
goToNextSlide();
setSelectedIndex(zeroBasedIndex);
setDraggable(shouldBeDraggable);
isFirstSlide();
isLastSlide();
getSelectedIndex();
getCarouselElement();
getSlides();
getSlide(zeroBasedIndex);
addSlide(slideHtml);
reset();
startSlideshow();
pauseSlideshow();
Looped with images
Add the isLooped
option to make the carousel cycle infinitely. It takes slides from the start and appends them to the end when going forwards, and in end to start going backwards.
Setup
var looped = new OdoCarousel(document.getElementById('looped'), {
isLooped: true
});
Add a slide
var slideHtml = '<div class="odo-carousel__slide">5</div>';
addSlide(slideHtml);
Jumped and Looped with pagination
By default, the carousel does not add pagination. To add pagination, add a pagination
option to the carousel. This demo also shows how you can change the easing of the animation with easing: 'ease'
.
Setup
var jumped = new OdoCarousel(document.getElementById('jumped'), {
isLooped: true,
isJumped: true,
pagination: true,
easing: 'ease'
});
Vertical and Looped
Carousels can be vertical too with isVertical
option. This demo changes the duration of the animation with animationSpeed: 500
. The paddles and pagination are customized with getNavPaddleHtml
and getPaginationHtml
. You have access to the carousel's templating method through OdoCarousel.template
.
Setup
var vertical = new OdoCarousel(document.getElementById('vertical'), {
isVertical: true,
isLooped: true,
animationSpeed: 500,
pagination: true,
template: {
paddleNextInner: '<svg viewBox="0 0 24 24"><path d="M7.4 8.3L6 9.7l6 6 6-6-1.4-1.4-4.6 4.6z"></path></svg>',
paddlePrevInner: '<svg viewBox="0 0 24 24"><path d="M16.6 15.7l1.4-1.4-6-6-6 6 1.4 1.4 4.6-4.6 4.6 4.6z"/></svg>'
},
getNavPaddleHtml: function () {
return '';
},
getPaginationHtml: function (instance) {
var totalSlides = instance.getSlides().length;
var previousPaddle = OdoCarousel.template(instance.options.template.paddlePrev, {
paddleInner: instance.options.template.paddlePrevInner,
});
var nextPaddle = OdoCarousel.template(instance.options.template.paddleNext, {
paddleInner: instance.options.template.paddleNextInner,
});
var dotsHtml = '';
for (var i = 0; i < totalSlides; i++) {
dotsHtml += OdoCarousel.template(instance.options.template.paginationDot, {
index: i,
index1: i + 1,
slideId: instance.getSlide(i).id,
});
}
var open = '<nav role="tablist" class="' + OdoCarousel.Classes.PAGINATION +
' ' + OdoCarousel.Classes.PADDLES + '">';
var close = '</nav>';
return open + previousPaddle + dotsHtml + nextPaddle + close;
}
});
Looped Multiple Neighbors
A slide neighbor is the slide which is beside another. You can change the number of neighbors the active slide has with the neighborCount
option. This one has 4
neighbors.
Markup
<div id="neighbors" class="odo-carousel">
<div class="odo-carousel__wrapper">
<div class="odo-carousel__element">
<div class="odo-carousel__slide" data-color="1">1</div>
<div class="odo-carousel__slide" data-color="2">2</div>
<div class="odo-carousel__slide" data-color="3">3</div>
<div class="odo-carousel__slide" data-color="4">4</div>
<div class="odo-carousel__slide" data-color="5">5</div>
<div class="odo-carousel__slide" data-color="6">6</div>
<div class="odo-carousel__slide" data-color="7">7</div>
<div class="odo-carousel__slide" data-color="8">8</div>
<div class="odo-carousel__slide" data-color="9">9</div>
<div class="odo-carousel__slide" data-color="10">10</div>
</div>
</div>
</div>
Setup
var neighbors = new OdoCarousel(document.getElementById('neighbors'), {
isLooped: true,
neighborCount: 4
});
Centered Slides
The isCentered
option will position the slides in the center of the carousel wrapper element. This works well when your slides are smaller than the carousel wrapper.
Setup
var centered = new OdoCarousel(document.getElementById('centered-demo'), {
isCentered: true,
});
Bidirectional Carousel with only 2 slides
Looped carousels containing only 2
slides need special rendering to allow bidirectional navigation. Simply setting isLooped: true
will properly enable this functionality.
Markup
<div id="bidirectional" class="odo-carousel">
<div class="odo-carousel__wrapper">
<div class="odo-carousel__element">
<div class="odo-carousel__slide" data-color="1">1</div>
<div class="odo-carousel__slide" data-color="2">2</div>
</div>
</div>
</div>
Setup
var bidirectional = new OdoCarousel(document.getElementById('bidirectional'), {
isLooped: true,
pagination: true
});
Slideshow
To autplay the carousel, you must start it with startSlideshow()
. If the carousel is not looped, the slideshow will stop at the end.
Setup
var slideshow = new OdoCarousel(document.getElementById('slideshow'), {
slideshowSpeed: 1500,
animationSpeed: 600
});
Playing and Pausing the Slideshow
startSlideshow();
pauseSlideshow();
Fading Carousel
These behave like slideshows. They have touch/pointer/mouse events bound to them and will change slides when it interprets a horizontal swipe. Devices without CSS transitions will not see a fade animation (IE9).
Slide Markup
Is the same as regular carousels, except the main carousel element has a odo-carousel--fade
class on it.
<div id="darth-fader" class="odo-carousel odo-carousel--fade">
<div class="odo-carousel__wrapper">
<div class="odo-carousel__element">
<div class="odo-carousel__slide" data-color="1">1</div>
<div class="odo-carousel__slide" data-color="2">2</div>
<div class="odo-carousel__slide" data-color="3">3</div>
<div class="odo-carousel__slide" data-color="4">4</div>
<div class="odo-carousel__slide" data-color="5">5</div>
</div>
</div>
</div>
Setup
The only extra option with fading carousels is crossfadeAmount
, which is a number between [inclusive] 0.0
and 1.0
. A crossfade of 1.0 means that both slides will fade at the same time. A crossfade of zero means the previous slide will wait until the next slide has completely faded in before it fades out.
var darthFader = new OdoCarousel(document.getElementById('darth-fader'), {
isFade: true,
isLooped: true
});
Events
Odo Carousel emits 3 events: WILL_NAVIGATE
, SLIDE_START
, and SLIDE_END
. If the preventDefault
method is called on the event object from the WILL_NAVIGATE
event, it will prevent the carousel from navigating. The SLIDE_START
and SLIDE_END
events contain useful properties for customizing your own carousel: event.from
index, event.to
index, and event.hasSlideChanged
(the slide could animate back to the closest slide instead of going to a new one).
var regular = new OdoCarousel(document.getElementById('regular'));
regular.on(OdoCarousel.EventType.SLIDE_END, function (event) {
console.log(event);
});
Options
These are the default options for the carousel. They can all be overridden.
Defaults: {
startIndex: 0,
isVertical: false,
isLooped: false,
isJumped: false,
isFade: false,
isCentered: false,
neighborCount: 1,
slideshowSpeed: 1000,
animationSpeed: 400,
crossfadeAmount: 0.875,
easing: 'cubic-bezier(0.250, 0.460, 0.450, 0.940)',
pagination: false,
getNavPaddleHtml: null,
getPaginationHtml: null,
template: {
paddles: '<nav class="odo-carousel__nav-paddles">{{ prev }}{{ next }}</nav>',
paddleNext: '<a href="javascript:void(0)" class="odo-carousel__nav-paddle odo-carousel__nav-next">{{ paddleInner }}</a>',
paddlePrev: '<a href="javascript:void(0)" class="odo-carousel__nav-paddle odo-carousel__nav-prev">{{ paddleInner }}</a>',
paddleNextInner: '<svg viewBox="75.4 27 461.2 738"><path d="M167.7 27l368.9 369-368.9 369-92.3-92.3 276.7-276.7-276.7-276.7z"/></svg>',
paddlePrevInner: '<svg viewBox="75.396 26.994 461.208 738.012"><path d="M444.336 765.006l-368.94-369.006 368.94-369.006 92.268 92.268-276.738 276.738 276.738 276.738z"/></svg>',
pagination: '<nav class="odo-carousel__pagination">{{ dots }}</nav>',
paginationDot: '<a href="javascript:void(0)" class="odo-carousel__pagination-dot" data-index="{{ index }}"></a>',
paginationDotSecondary: '<a href="javascript:void(0)" class="odo-carousel__pagination-dot" data-index="{{ index }}" data-secondary-index="{{ secondaryIndex }}" data-hidden="{{ hidden }}"></a>',
},
}
Templates
The carousel uses a simple template engine to replace double curlies with data for the paddles and pagination. You can either change a single template with the the template options, or completely change the structure using getNavPaddleHtml
and getPaginationHtml
. Here’s a few examples of how the templates work which you can paste in the console.
OdoCarousel.template("Today is {{ day }}", {
day: 'Friday'
}); // "Today is Friday"
OdoCarousel.template("Today is {{ month.day }}", {
month: {
day: "Friday"
}
}); // "Today is Friday
OdoCarousel.template("Today is {{ day }}", {
dayOfTheWeek: 'Friday',
day: function () {
return this.dayOfTheWeek;
}
}); // "Today is Friday"
To customize the structure of paddles or pagination, use the getNavPaddleHtml
and getPaginationHtml
methods, respectively. Like the Vertical and Looped example, you need to return a string for the carousel to use (it can be empty). Click events on the carousel are delegated, so anything inside the main carousel element with the pagination dot class or next/previous class will trigger the carousel to navigate.