Creating Custom Plugins
Plugin Architecture
Embla Carousel is designed to be highly extensible. While the core engine handles the complex physics and scroll logic, additional features like Autoplay, Wheel Gestures, or Class Toggling are implemented as plugins.
A plugin is essentially a function that returns an object adhering to the Embla plugin interface. This architecture allows you to inject custom logic into the carousel's lifecycle without modifying the core library.
Anatomy of a Plugin
A plugin must return an object containing a unique name, an init method, and a destroy method. It can also expose custom methods that users can access via the Embla API.
const MyCustomPlugin = (options = {}) => {
return {
name: 'myCustomPlugin',
options,
init: (emblaApi, optionsHandler) => {
// Logic to run when the carousel initializes
},
destroy: () => {
// Logic to run when the carousel is destroyed
},
// Optional: Expose custom methods
myPluginMethod: () => {
console.log('Plugin method called!')
}
}
}
Properties and Methods
| Property | Type | Description |
| :--- | :--- | :--- |
| name | string | A unique identifier for your plugin. This is used as the key in the emblaApi.plugins() object. |
| options | Object | Stores the configuration passed to the plugin. |
| init | Function | Called by Embla when the carousel is initialized or re-initialized. Receives the emblaApi and an optionsHandler. |
| destroy | Function | Called when the carousel is destroyed. Use this to remove event listeners or clear timers. |
Lifecycle Hooks
init(emblaApi, optionsHandler)
The init method is where you set up your plugin's logic. You have full access to the emblaApi, allowing you to subscribe to events like select, scroll, or pointerDown.
The optionsHandler provides a way to manage responsive options and breakpoints if your plugin supports them.
destroy()
To prevent memory leaks, always clean up side effects in the destroy method. This includes:
- Unsubscribing from Embla events (
emblaApi.off). - Removing DOM event listeners.
- Clearing
setTimeoutorsetInterval.
TypeScript Support
If you are using TypeScript, you can leverage the EmblaCarouselPluginType to ensure your plugin matches the expected internal structure.
import { EmblaCarouselPluginType } from 'embla-carousel'
export type MyPluginOptionsType = {
active?: boolean
}
const defaultOptions: MyPluginOptionsType = {
active: true
}
function MyPlugin(userOptions: MyPluginOptionsType = {}): EmblaCarouselPluginType {
const options = { ...defaultOptions, ...userOptions }
let emblaApi: EmblaCarouselType
function init(
api: EmblaCarouselType,
optionsHandler: OptionsHandlerType
): void {
emblaApi = api
if (!options.active) return
emblaApi.on('select', logSelection)
}
function destroy(): void {
emblaApi.off('select', logSelection)
}
function logSelection(): void {
console.log('Selected snap is:', emblaApi.selectedSnap())
}
return {
name: 'myPlugin',
options,
init,
destroy
}
}
Accessing Plugin Methods
Users can interact with your plugin's public methods through the plugins() method on the Embla API.
const emblaApi = EmblaCarousel(viewportNode, {}, [MyPlugin()])
// Access your custom plugin
const myPlugin = emblaApi.plugins().myPlugin
Practical Example: A Slide Scaler
Below is a complete example of a plugin that scales the active slide and shrinks the inactive ones.
const SlideScale = (userOptions = {}) => {
const options = { scale: 0.8, ...userOptions }
let emblaApi
const applyStyles = () => {
const slides = emblaApi.slideNodes()
const selected = emblaApi.selectedSnap()
slides.forEach((slide, index) => {
const scale = index === selected ? 1 : options.scale
slide.style.transform = `scale(${scale})`
slide.style.transition = 'transform 0.2s ease-in-out'
})
}
return {
name: 'slideScale',
options,
init: (api) => {
emblaApi = api
emblaApi.on('select', applyStyles)
emblaApi.on('init', applyStyles)
emblaApi.on('reInit', applyStyles)
},
destroy: () => {
// Clean up styles if necessary
emblaApi.slideNodes().forEach(slide => {
slide.style.transform = ''
})
}
}
}
// Usage
const emblaApi = EmblaCarousel(viewport, {}, [SlideScale({ scale: 0.9 })])