Vue

Embla Carousel provides a wrapper for Vue that ensures seamless integration of the carousel into your Vue project and automatic cleanup on component unmount.

Start by installing the Embla Carousel npm package and add it to your dependencies.

npm install embla-carousel-vue --save

Note: embla-carousel-vue only supports Vue 3 and up. However, you can use the core package that embla-carousel-vue is using under the hood, and re-create the behaviour of embla-carousel-vue. Here's an example of how you can use Embla Carousel with Vue 2 Options API.


The component structure

A recommended setup uses an overflow wrapper and a scroll container, though the outer wrapper is optional. The element with the class name embla__viewport serves as both the root and the overflow wrapper. To avoid drag conflicts, place navigation buttons outside the viewport. Start by adding the following structure to your carousel:

<script setup>import useEmblaCarousel from 'embla-carousel-vue'
const [emblaRef] = useEmblaCarousel()</script>
<template>  <div class="embla">    <div class="embla__viewport" ref="emblaRef">      <div class="embla__container">        <div class="embla__slide">Slide 1</div>        <div class="embla__slide">Slide 2</div>        <div class="embla__slide">Slide 3</div>      </div>    </div>
    <button class="embla__prev">Scroll to prev</button>    <button class="embla__next">Scroll to next</button>  </div></template>

The element with the classname embla__viewport acts as an overflow wrapper, ensuring that any scroll overflow is hidden. The element with the classname embla__container is the scrollable area that holds and moves the slides. Add the following CSS to style these elements:

<style scoped>.embla__viewport {  overflow: hidden;}
.embla__container {  display: flex;  touch-action: pan-y pinch-zoom;}
.embla__slide {  flex: 0 0 100%;  min-width: 0;}</style>

Use the useEmblaCarousel composable and pass your options as the first argument. You can access the API directly from the composable, and use it to control the carousel or respond to user actions, as shown below:

<script setup>import useEmblaCarousel from 'embla-carousel-vue'
const [emblaRef, emblaApi] = useEmblaCarousel({ loop: false })
const goToPrev = () => emblaApi.value?.goToPrev()const goToNext = () => emblaApi.value?.goToNext()</script>
<template>  <div class="embla">    <div class="embla__viewport" ref="emblaRef">      <div class="embla__container">        <div class="embla__slide">Slide 1</div>        <div class="embla__slide">Slide 2</div>        <div class="embla__slide">Slide 3</div>      </div>    </div>
    <button class="embla__prev" @click="goToPrev">Scroll to prev</button>    <button class="embla__next" @click="goToNext">Scroll to next</button>  </div></template>

Adding plugins

Start by installing the plugin you want to use. In this example, we're going to install the Autoplay plugin:

npm install embla-carousel-autoplay --save

You can pass an optional plugin array as the second argument to the useEmblaCarousel composable. Here's how to extend the carousel from the previous example with Autoplay:

<script setup>import { watch } from 'vue'import useEmblaCarousel from 'embla-carousel-vue'import Autoplay from 'embla-carousel-autoplay'
const [emblaRef, emblaApi] = useEmblaCarousel({ loop: false }, [Autoplay()])
const goToPrev = () => emblaApi.value?.goToPrev()const goToNext = () => emblaApi.value?.goToNext()
watch(  emblaApi,  (api) => {    if (!api) return    api.plugins().autoplay?.play()  },  { immediate: true })</script>
<template>  <div class="embla">    <div class="embla__viewport" ref="emblaRef">      <div class="embla__container">        <div class="embla__slide">Slide 1</div>        <div class="embla__slide">Slide 2</div>        <div class="embla__slide">Slide 3</div>      </div>    </div>
    <button class="embla__prev" @click="goToPrev">Scroll to prev</button>    <button class="embla__next" @click="goToNext">Scroll to next</button>  </div></template>

Congratulations! You just created your first Embla Carousel component.

Edit this page on GitHub