Events
Embla Carousel provides a set of events that allow you to hook into its lifecycle and react to state changes. By using these events, you can build custom pagination, navigation buttons, parallax effects, and more.
Usage
Events are managed through the emblaApi instance. You can subscribe to events using the .on() method and unsubscribe using .off().
Subscribing to events
The callback function receives the emblaApi instance as the first argument and the event name (or detailed event object) as the second.
const emblaApi = EmblaCarousel(viewportNode)
const onSelect = (emblaApi) => {
console.log(`Selected snap index is: ${emblaApi.selectedSnap()}`)
}
emblaApi.on('select', onSelect)
Unsubscribing from events
To prevent memory leaks, especially in component-based frameworks like React or Vue, ensure you unsubscribe from events when they are no longer needed.
emblaApi.off('select', onSelect)
Available Events
| Event | Description |
| :--- | :--- |
| init | Fired when the carousel is initialized for the first time. |
| reInit | Fired when the .reInit() method is called, often after window resize or content changes. |
| destroy | Fired when the carousel is destroyed using the .destroy() method. |
| select | Fired when a new snap point has been selected. |
| scroll | Fired while the carousel is scrolling. Useful for parallax or progress indicators. |
| settle | Fired when the carousel has come to a complete stop after scrolling. |
| resize | Fired when the carousel container or slide sizes change. |
| pointerDown | Fired when a user initiates a pointer interaction (mouse or touch). |
| pointerUp | Fired when a user releases a pointer interaction. |
| slidesInView | Fired when slides enter the viewport (calculated based on inViewThreshold). |
| slidesNotInView | Fired when slides leave the viewport. |
Event Details
Some events provide additional metadata through the second argument. For example, the slidesInView and slidesNotInView events provide an array of slide indices.
emblaApi.on('slidesInView', (emblaApi, event) => {
const { slidesInView } = emblaApi.internalEngine()
console.log('Slides currently in view:', slidesInView)
})
Framework Examples
React
In React, you should set up your event listeners inside a useEffect hook, ensuring you have a check for the emblaApi instance.
import React, { useEffect, useCallback } from 'react'
import useEmblaCarousel from 'embla-carousel-react'
export const EmblaCarousel = () => {
const [emblaRef, emblaApi] = useEmblaCarousel()
const onSelect = useCallback((emblaApi) => {
console.log(`Selected snap: ${emblaApi.selectedSnap()}`)
}, [])
useEffect(() => {
if (!emblaApi) return
emblaApi.on('select', onSelect)
// Clean up listener on unmount
return () => {
emblaApi.off('select', onSelect)
}
}, [emblaApi, onSelect])
return (
<div className="embla" ref={emblaRef}>
<div className="embla__container">
<div className="embla__slide">Slide 1</div>
<div className="embla__slide">Slide 2</div>
</div>
</div>
)
}
Vue
In Vue, use a watch or the onMounted lifecycle hook to access the API and register listeners.
<script setup>
import { watch } from 'vue'
import useEmblaCarousel from 'embla-carousel-vue'
const [emblaRef, emblaApi] = useEmblaCarousel()
watch(emblaApi, (api) => {
if (!api) return
api.on('select', () => {
console.log('Slide selected in Vue!')
})
})
</script>
<template>
<div class="embla" ref="emblaRef">
<div class="embla__container">
<div class="embla__slide">Slide 1</div>
<div class="embla__slide">Slide 2</div>
</div>
</div>
</template>
Svelte
In Svelte, the useEmblaCarousel action provides an emblainit event that returns the API instance, which you can then use to attach further listeners.
<script>
import useEmblaCarousel from 'embla-carousel-svelte'
let emblaApi
function onInit(event) {
emblaApi = event.detail
emblaApi.on('select', () => {
console.log('Selected in Svelte')
})
}
</script>
<div
class="embla"
use:useEmblaCarousel
on:emblainit={onInit}
>
<div class="embla__container">
<div class="embla__slide">Slide 1</div>
<div class="embla__slide">Slide 2</div>
</div>
</div>