Embla Carousel πŸ€

September 07, 2019
|
9 min read

Just another carousel? 🀨

No, this is something else. My good friend David Cetinkaya has studied physics within JavaScript and created this smooth and light weight carousel. His own words:

Embla's purpose is to provide a low level carousel and allow developers to extend it by using its available methods. Extend it with some very basic JavaScript and build awesome physics simulated carousels. It's dependency free and 100% open source.

Show me the demo already πŸ”₯

Below the carousel I've appended some of the available options, just toggle between the boolean states by clicking on them. I've also appended two states that comes from the Embla API.

Visit the github page to view all the options and API.

1.
2.
3.
4.
5.
Loop

Align the slides relative to the carousel viewport.

Drag free

Determines if the carousel should snap to a slide position after mouse & touch interactions.

Draggable

Allow mouse & touch interactions to scroll the carousel.

Hide dots

Not within the options, but created with the embla.scrollSnapList() and embla.selectedScrollSnap() api.

Hide arrows

Not within the options, but created with the embla.scrollPrev() and embla.scrollNext() api.

Is it easy to use?

Yes, with some decent knowledge. The package doesn't come with e.g. predefined arrows and dots, you have to use your knowledge to create them using the API. But at the same time, it's not rocket science πŸš€

I will showcase Embla with the React.js wrapper.

Basic

Here's the most basic example, it's just the carousel as it is.

import React, { useState } from 'react'
import EmblaCarouselReact from 'embla-carousel-react'

const Carousel = () => {
  const [embla, setEmbla] = useState(null);

  return (
		<EmblaCarouselReact
			htmlTagName="div"
			emblaRef={setEmbla}
		>
			<div style={{ display: 'flex' }}>
				<div style={{ flex: '0 0 100%' }}>Slide 1</div>
				<div style={{ flex: '0 0 100%' }}>Slide 2</div>
				<div style={{ flex: '0 0 100%' }}>Slide 3</div>
			</div>
		</EmblaCarouselReact>
  );
};

export default Carousel;

Options

You can just send your desired options to Embla through its options prop. The defined options below are the default ones.

...

const options = {
	align: 'center',
  containerSelector: '*',
  slidesToScroll: 1,
  containScroll: false,
  draggable: true,
  dragFree: false,
  loop: false,
  speed: 10,
  startIndex: 0,
  selectedClass: 'is-selected',
  draggableClass: 'is-draggable',
  draggingClass: 'is-dragging'
};

return (
	<EmblaCarouselReact
		htmlTagName="div"
		emblaRef={setEmbla}
		options={options}
	>
		...
	</EmblaCarouselReact>
);

...

Previous & next buttons

Append the opportunity to scroll between previous and next slides.

...

const onScrollPrev = useCallback(() => embla.scrollPrev(), [embla]);
const onScrollNext = useCallback(() => embla.scrollNext(), [embla]);

return (
	...
	
	<>
		<button
			type="button"
			onClick={onScrollPrev}
		>
			Previous
		</button>
		<button
			type="button"
			onClick={onScrollNext}
		>
			Next
		</button>
	</>
	
	...
);

...

Dots

We'll count the amount of slides with embla.scrollSnapList() and listen for which slide is active with embla.selectedScrollSnap().

...

const [slide, setSlide] = useState(0);

useEffect(() => {
	if (embla) {
		embla.on('select', () => setSlide(embla.selectedScrollSnap()));
	}
}, [embla]);

const renderDots = useCallback(() => {
	if (embla) {
		return embla.scrollSnapList().map((snap, index) => (
			<button
				key={index}
				active={index === slide}
				aria-label={`Scroll to slide number ${index + 1}`}
				type="button"
				onClick={() => embla.scrollTo(index)}
			/>
		));
	}

	return null;
}, [embla, slide]);

return (
	...
	
	${renderDots()}
	
	...
);

...

More advanced previous & next buttons

If you've set the loop option to false you probably want to disable the button if you can't go further. Is this possible? Yes, we'll use embla.canScrollPrev() and embla.canScrollNext().

...

const [canScrollPrev, setCanScrollPrev] = useState(false);
const [canScrollNext, setCanScrollNext] = useState(false);
const onScrollPrev = useCallback(() => embla.scrollPrev(), [embla]);
const onScrollNext = useCallback(() => embla.scrollNext(), [embla]);

useEffect(() => {
	if (embla) {
		embla.on('select', () => {
			setCanScrollPrev(embla.canScrollPrev());
			setCanScrollNext(embla.canScrollNext());
		});
	}
}, [embla]);

return (
	...
	
	<>
		<button
			type="button"
			onClick={onScrollPrev}
			disabled={!canScrollPrev}
		>
			Previous
		</button>
		<button
			type="button"
			onClick={onScrollNext}
			disabled={!canScrollNext}
		>
			Next
		</button>
	</>
	
	...
);

...

Want to read more? πŸ“š

There's so much more to this carousel. Visit the github page or his own demo page to read more.

Are you convinced to use this carousel? Yes, me too. Do you want to know something even more awesome? It's dependency free and 100% open source 🎈