Plugins
You can extend Embla Carousel with additional features by using plugins. A complete list of official plugins is available here.
Installation
All official plugins are published as separate NPM packages. Each package name starts with the embla-carousel prefix, followed by the plugin's unique name.
For example, to install the Autoplay plugin:
<script src="https://unpkg.com/embla-carousel-autoplay/embla-carousel-autoplay.umd.js"></script>npm install embla-carousel-autoplay --savepnpm add embla-carousel-autoplayyarn add embla-carousel-autoplayUsage
The Embla Carousel constructor accepts an array of plugins. Each plugin can provide its own options, methods, and events.
Adding a plugin
The constructor's plugin array is the standard way to add plugins to Embla Carousel. In the example below, the Autoplay plugin is added to the carousel:
import EmblaCarousel from 'embla-carousel'import Autoplay from 'embla-carousel-autoplay'
const wrapperNode = document.querySelector('.embla')const viewportNode = wrapperNode.querySelector('.embla__viewport')
const emblaApi = EmblaCarousel(viewportNode, { loop: true }, [Autoplay()])
emblaApi.plugins().autoplay?.play()<div class="embla"> <div class="embla__viewport"> <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></div>import React, { useEffect } from 'react'import useEmblaCarousel from 'embla-carousel-react'import Autoplay from 'embla-carousel-autoplay'
export function EmblaCarousel() { const [emblaRef, emblaApi] = useEmblaCarousel({ loop: true }, [Autoplay()])
useEffect(() => { if (!emblaApi) return emblaApi.plugins().autoplay?.play() }, [emblaApi])
return ( <div className="embla"> <div className="embla__viewport" ref={emblaRef}> <div className="embla__container"> <div className="embla__slide">Slide 1</div> <div className="embla__slide">Slide 2</div> <div className="embla__slide">Slide 3</div> </div> </div> </div> )}<script setup>import { watch } from 'vue'import useEmblaCarousel from 'embla-carousel-vue'import Autoplay from 'embla-carousel-autoplay'
const [emblaRef, emblaApi] = useEmblaCarousel({ loop: true }, [Autoplay()])
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> </div></template>import { createEffect, on } from 'solid-js'import useEmblaCarousel from 'embla-carousel-solid'import Autoplay from 'embla-carousel-autoplay'
export function EmblaCarousel() { const [emblaRef, emblaApi] = useEmblaCarousel( () => ({ loop: true }), () => [Autoplay()] )
createEffect( on(emblaApi, (api) => { if (!api) return api.plugins().autoplay?.play() }) )
return ( <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> </div> )}<script> import useEmblaCarousel from 'embla-carousel-svelte' import Autoplay from 'embla-carousel-autoplay'
let options = { loop: true } let plugins = [Autoplay()]
const onInit = (event) => { emblaApi = event.detail emblaApi.plugins().autoplay?.play() }</script>
<div class="embla"> <div class="embla__viewport" on:emblainit={onInit} use:useEmblaCarousel={{ options, plugins }} > <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></div>Note that you can update the plugins passed to the Embla Carousel
constructor after initialization using the
reInit method.
Constructor options
Plugins can accept their own specific options as the first argument to the plugin constructor. This allows you to configure the plugin to suit your needs:
import EmblaCarousel from 'embla-carousel'import Autoplay from 'embla-carousel-autoplay'
const wrapperNode = document.querySelector('.embla')const viewportNode = wrapperNode.querySelector('.embla__viewport')
const emblaApi = EmblaCarousel(viewportNode, { loop: true }, [ Autoplay({ delay: 4000 })])
emblaApi.plugins().autoplay?.play()<div class="embla"> <div class="embla__viewport"> <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></div>import React, { useEffect } from 'react'import useEmblaCarousel from 'embla-carousel-react'import Autoplay from 'embla-carousel-autoplay'
export function EmblaCarousel() { const [emblaRef, emblaApi] = useEmblaCarousel({ loop: true }, [ Autoplay({ delay: 4000 }) ])
useEffect(() => { if (!emblaApi) return emblaApi.plugins().autoplay?.play() }, [emblaApi])
return ( <div className="embla"> <div className="embla__viewport" ref={emblaRef}> <div className="embla__container"> <div className="embla__slide">Slide 1</div> <div className="embla__slide">Slide 2</div> <div className="embla__slide">Slide 3</div> </div> </div> </div> )}<script setup>import { watch } from 'vue'import useEmblaCarousel from 'embla-carousel-vue'import Autoplay from 'embla-carousel-autoplay'
const [emblaRef, emblaApi] = useEmblaCarousel({ loop: true }, [ Autoplay({ delay: 4000 })])
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> </div></template>import { createEffect, on } from 'solid-js'import useEmblaCarousel from 'embla-carousel-solid'import Autoplay from 'embla-carousel-autoplay'
export function EmblaCarousel() { const [emblaRef, emblaApi] = useEmblaCarousel( () => ({ loop: true }), () => [Autoplay({ delay: 4000 })] )
createEffect( on(emblaApi, (api) => { if (!api) return api.plugins().autoplay?.play() }) )
return ( <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> </div> )}<script> import useEmblaCarousel from 'embla-carousel-svelte' import Autoplay from 'embla-carousel-autoplay'
let options = { loop: true } let plugins = [Autoplay({ delay: 4000 })]
const onInit = (event) => { emblaApi = event.detail emblaApi.plugins().autoplay?.play() }</script>
<div class="embla"> <div class="embla__viewport" on:emblainit={onInit} use:useEmblaCarousel={{ options, plugins }} > <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></div>Global options
All official plugins allow you to set global options that apply to every carousel instance. This lets you override the default plugin settings with your own preferences:
import EmblaCarousel from 'embla-carousel'import Autoplay from 'embla-carousel-autoplay'
Autoplay.globalOptions = { delay: 4000 }
const wrapperNode = document.querySelector('.embla')const viewportNode = wrapperNode.querySelector('.embla__viewport')
const emblaApi = EmblaCarousel(viewportNode, { loop: true }, [Autoplay()])
emblaApi.plugins().autoplay?.play()<div class="embla"> <div class="embla__viewport"> <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></div>import React, { useEffect } from 'react'import useEmblaCarousel from 'embla-carousel-react'import Autoplay from 'embla-carousel-autoplay'
Autoplay.globalOptions = { delay: 4000 }
export function EmblaCarousel() { const [emblaRef, emblaApi] = useEmblaCarousel({ loop: true }, [Autoplay()])
useEffect(() => { if (!emblaApi) return emblaApi.plugins().autoplay?.play() }, [emblaApi])
return ( <div className="embla"> <div className="embla__viewport" ref={emblaRef}> <div className="embla__container"> <div className="embla__slide">Slide 1</div> <div className="embla__slide">Slide 2</div> <div className="embla__slide">Slide 3</div> </div> </div> </div> )}<script setup>import { watch } from 'vue'import useEmblaCarousel from 'embla-carousel-vue'import Autoplay from 'embla-carousel-autoplay'
Autoplay.globalOptions = { delay: 4000 }
const [emblaRef, emblaApi] = useEmblaCarousel({ loop: true }, [Autoplay()])
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> </div></template>import { createEffect, on } from 'solid-js'import useEmblaCarousel from 'embla-carousel-solid'import Autoplay from 'embla-carousel-autoplay'
Autoplay.globalOptions = { delay: 4000 }
export function EmblaCarousel() { const [emblaRef, emblaApi] = useEmblaCarousel( () => ({ loop: true }), () => [Autoplay()] )
createEffect( on(emblaApi, (api) => { if (!api) return api.plugins().autoplay?.play() }) )
return ( <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> </div> )}<script> import useEmblaCarousel from 'embla-carousel-svelte' import Autoplay from 'embla-carousel-autoplay'
Autoplay.globalOptions = { delay: 4000 }
let options = { loop: true } let plugins = [Autoplay()]
const onInit = (event) => { emblaApi = event.detail emblaApi.plugins().autoplay?.play() }</script>
<div class="embla"> <div class="embla__viewport" on:emblainit={onInit} use:useEmblaCarousel={{ options, plugins }} > <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></div>Make sure to assign global options before initializing any carousel and only once. Reassigning global options may cause unexpected behavior and lead to confusing code.
Calling methods
Some plugins also provide their own API methods. You can access these plugin methods using the plugins method, as shown in the example below:
import EmblaCarousel from 'embla-carousel'import Autoplay from 'embla-carousel-autoplay'
const wrapperNode = document.querySelector('.embla')const viewportNode = wrapperNode.querySelector('.embla__viewport')
const emblaApi = EmblaCarousel(viewportNode, { loop: true }, [Autoplay()])
emblaApi.plugins().autoplay?.play()<div class="embla"> <div class="embla__viewport"> <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></div>import React, { useEffect } from 'react'import useEmblaCarousel from 'embla-carousel-react'import Autoplay from 'embla-carousel-autoplay'
export function EmblaCarousel() { const [emblaRef, emblaApi] = useEmblaCarousel({ loop: true }, [Autoplay()])
useEffect(() => { if (!emblaApi) return emblaApi.plugins().autoplay?.play() }, [emblaApi])
return ( <div className="embla"> <div className="embla__viewport" ref={emblaRef}> <div className="embla__container"> <div className="embla__slide">Slide 1</div> <div className="embla__slide">Slide 2</div> <div className="embla__slide">Slide 3</div> </div> </div> </div> )}<script setup>import { watch } from 'vue'import useEmblaCarousel from 'embla-carousel-vue'import Autoplay from 'embla-carousel-autoplay'
const [emblaRef, emblaApi] = useEmblaCarousel({ loop: true }, [Autoplay()])
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> </div></template>import { createEffect, on } from 'solid-js'import useEmblaCarousel from 'embla-carousel-solid'import Autoplay from 'embla-carousel-autoplay'
export function EmblaCarousel() { const [emblaRef, emblaApi] = useEmblaCarousel( () => ({ loop: true }), () => [Autoplay()] )
createEffect( on(emblaApi, (api) => { if (!api) return api.plugins().autoplay?.play() }) )
return ( <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> </div> )}<script> import useEmblaCarousel from 'embla-carousel-svelte' import Autoplay from 'embla-carousel-autoplay'
let options = { loop: true } let plugins = [Autoplay()]
const onInit = (event) => { emblaApi = event.detail emblaApi.plugins().autoplay?.play() }</script>
<div class="embla"> <div class="embla__viewport" on:emblainit={onInit} use:useEmblaCarousel={{ options, plugins }} > <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></div>Note: Starting with Svelte 5, the on: event handlers have been
deprecated. However, on:emblainit will remain for backward
compatibility.
Adding event listeners
Some plugins emit their own events, structured as <plugin-name>:eventname. Adding and removing plugin event listeners works the same way as with native Embla events.
The example below shows how to add an event listener to the Autoplay plugin:
import EmblaCarousel from 'embla-carousel'import Autoplay from 'embla-carousel-autoplay'
const wrapperNode = document.querySelector('.embla')const viewportNode = wrapperNode.querySelector('.embla__viewport')
const emblaApi = EmblaCarousel(viewportNode, { loop: true }, [Autoplay()])
const logAutoplayStart = (emblaApi, event) => { console.log(`${event.type} fired`)}
emblaApi.on('autoplay:play', logAutoplayStart)emblaApi.plugins().autoplay?.play()<div class="embla"> <div class="embla__viewport"> <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></div>import React, { useEffect } from 'react'import useEmblaCarousel from 'embla-carousel-react'import Autoplay from 'embla-carousel-autoplay'
export function EmblaCarousel() { const [emblaRef, emblaApi] = useEmblaCarousel({ loop: true }, [Autoplay()])
const logAutoplayStart = (emblaApi, event) => { console.log(`${event.type} fired`) }
useEffect(() => { if (!emblaApi) return
emblaApi.on('autoplay:play', logAutoplayStart) emblaApi.plugins().autoplay?.play() }, [emblaApi])
return ( <div className="embla"> <div className="embla__viewport" ref={emblaRef}> <div className="embla__container"> <div className="embla__slide">Slide 1</div> <div className="embla__slide">Slide 2</div> <div className="embla__slide">Slide 3</div> </div> </div> </div> )}<script setup>import { watch } from 'vue'import useEmblaCarousel from 'embla-carousel-vue'import Autoplay from 'embla-carousel-autoplay'
const [emblaRef, emblaApi] = useEmblaCarousel({ loop: true }, [Autoplay()])
const logAutoplayStart = (emblaApi, event) => { console.log(`${event.type} fired`)}
watch( emblaApi, (api) => { if (!api) return
api.on('autoplay:play', logAutoplayStart) 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> </div></template>import { createEffect, on } from 'solid-js'import useEmblaCarousel from 'embla-carousel-solid'import Autoplay from 'embla-carousel-autoplay'
export function EmblaCarousel() { const [emblaRef, emblaApi] = useEmblaCarousel( () => ({ loop: true }), () => [Autoplay()] )
const logAutoplayStart = (emblaApi, event) => { console.log(`${event.type} fired`) }
createEffect( on(emblaApi, (api) => { if (!api) return
api.on('autoplay:play', logAutoplayStart) api.plugins().autoplay?.play() }) )
return ( <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> </div> )}<script> import useEmblaCarousel from 'embla-carousel-svelte' import Autoplay from 'embla-carousel-autoplay'
let options = { loop: true } let plugins = [Autoplay()]
const logAutoplayStart = (emblaApi, event) => { console.log(`${event.type} fired`) }
const onInit = (event) => { emblaApi = event.detail
emblaApi.on('autoplay:play', logAutoplayStart) emblaApi.plugins().autoplay?.play() }</script>
<div class="embla"> <div class="embla__viewport" on:emblainit={onInit} use:useEmblaCarousel={{ options, plugins }} > <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></div>Note: Starting with Svelte 5, the on: event handlers have been
deprecated. However, on:emblainit will remain for backward
compatibility.
TypeScript
The EmblaPluginType is exported from the core embla-carousel package and can be used as shown below:
import EmblaCarousel, { EmblaPluginType } from 'embla-carousel'import Autoplay from 'embla-carousel-autoplay'
const wrapperNode = <HTMLElement>document.querySelector('.embla')const viewportNode = <HTMLElement>wrapperNode.querySelector('.embla__viewport')
const plugins: EmblaPluginType[] = [Autoplay()]const emblaApi = EmblaCarousel(viewportNode, { loop: true }, plugins)
emblaApi.plugins().autoplay?.play()<div class="embla"> <div class="embla__viewport"> <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></div>import React, { useState, useEffect } from 'react'import { EmblaPluginType } from 'embla-carousel'import useEmblaCarousel from 'embla-carousel-react'import Autoplay from 'embla-carousel-autoplay'
export function EmblaCarousel() { const [plugins, setPlugins] = useState<EmblaPluginType[]>([Autoplay()]) const [emblaRef, emblaApi] = useEmblaCarousel({ loop: true }, plugins)
useEffect(() => { if (!emblaApi) return emblaApi.plugins().autoplay?.play() }, [emblaApi])
return ( <div className="embla"> <div className="embla__viewport" ref={emblaRef}> <div className="embla__container"> <div className="embla__slide">Slide 1</div> <div className="embla__slide">Slide 2</div> <div className="embla__slide">Slide 3</div> </div> </div> </div> )}If you're using pnpm, you need to install embla-carousel as a
devDependency when importing types from it like demonstrated above.
This is because even though embla-carousel-react has embla-carousel as
a dependency, pnpm makes nested dependencies inaccessible by design.
<script setup lang="ts">import { watch, ref } from 'vue'import { EmblaPluginType } from 'embla-carousel'import useEmblaCarousel from 'embla-carousel-vue'import Autoplay from 'embla-carousel-autoplay'
const plugins = ref<EmblaPluginType[]>([Autoplay()])const [emblaRef, emblaApi] = useEmblaCarousel({ loop: true }, plugins)
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> </div></template>If you're using pnpm, you need to install embla-carousel as a
devDependency when importing types from it like demonstrated above.
This is because even though embla-carousel-vue has embla-carousel as a
dependency, pnpm makes nested dependencies inaccessible by design.
import { createEffect, createSignal, on } from 'solid-js'import { EmblaPluginType } from 'embla-carousel'import useEmblaCarousel from 'embla-carousel-solid'import Autoplay from 'embla-carousel-autoplay'
export function EmblaCarousel() { const [plugins, setPlugins] = createSignal<EmblaPluginType[]>([Autoplay()]) const [emblaRef, emblaApi] = useEmblaCarousel(() => ({ loop: true }), plugins)
createEffect( on(emblaApi, (api) => { if (!api) return api.plugins().autoplay?.play() }) )
return ( <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> </div> )}If you're using pnpm, you need to install embla-carousel as a
devDependency when importing types from it like demonstrated above.
This is because even though embla-carousel-solid has embla-carousel as
a dependency, pnpm makes nested dependencies inaccessible by design.
<script lang="ts"> import { EmblaCarouselType, EmblaOptionsType, EmblaPluginType } from 'embla-carousel' import useEmblaCarousel from 'embla-carousel-svelte' import Autoplay from 'embla-carousel-autoplay'
let emblaApi: EmblaCarouselType let options: EmblaOptionsType = { loop: true } let plugins: EmblaPluginType[] = [Autoplay()]
const onInit = (event: CustomEvent<EmblaCarouselType>): void => { emblaApi = event.detail emblaApi.plugins().autoplay?.play() }</script>
<div class="embla"> <div class="embla__viewport" on:emblainit={onInit} use:useEmblaCarousel={{ options, plugins }} > <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></div>If you're using pnpm, you need to install embla-carousel as a
devDependency when importing types from it like demonstrated above.
This is because even though embla-carousel-svelte has embla-carousel
as a dependency, pnpm makes nested dependencies inaccessible by design.