Skip to content

[Enhancement]: Add filters for extending Embla Carousel options and plugins #144

@sunmorgn

Description

@sunmorgn

Feature description

Expose stable JavaScript filters for full developer control over the Embla Carousel initialization used by rtCarousel.

Currently rtCarousel initializes Embla internally in view.ts and only exposes a fixed subset of Embla options through block attributes. It also only supports the built-in Autoplay plugin. It would be useful to provide extension hooks so projects can modify the final Embla options and add Embla plugins without forking rtCarousel.

Suggested filters:

const filteredOptions = applyFilters(
    'rtcamp.carouselKit.emblaOptions',
    options,
    {
        context,
        root: element,
        viewport,
        dynamicListContainer,
    }
);

const filteredPlugins = applyFilters(
    'rtcamp.carouselKit.emblaPlugins',
    plugins,
    {
        context,
        options: filteredOptions,
        root: element,
        viewport,
        dynamicListContainer,
    }
);

const embla = EmblaCarousel(
    viewport,
    filteredOptions,
    filteredPlugins
);

This would provide a one-stop extension point for advanced use cases:

  • Add Embla plugins such as Auto Height, Class Names, Fade, Wheel Gestures, or Auto Scroll.
  • Adjust Embla options that rtCarousel does not currently expose, such as duration, dragThreshold, skipSnaps, startIndex, inViewThreshold, watchFocus, watchDrag, watchResize, watchSlides, active, and breakpoints.
  • Target individual carousel instances using the root element, viewport, context, classes, or data attributes.
  • Keep the core plugin focused while allowing site-specific advanced behavior.

Problem it solves

Right now, adding Embla features like Auto Height, Class Names, or advanced option control requires modifying or forking rtCarousel because view.ts creates the Embla instance directly and does not expose a supported extension point.

Some JSON-serializable options can be worked around by filtering rendered block markup and changing data-wp-context, but that does not support Embla plugins, function-valued options, or clean runtime customization. DOM-level manipulation of the initialized Embla instance is brittle because it depends on internal implementation details.

A stable initialization hook would let developers customize Embla behavior while keeping rtCarousel upgradeable.

Describe alternatives you've considered

  • Forking rtCarousel and adding specific Embla plugins directly.
  • Creating a companion plugin that manipulates the initialized Embla instance from the DOM.
  • Filtering rendered block markup to modify data-wp-context.
  • Adding individual block settings for each Embla option or Embla plugin.

Forking increases maintenance cost. DOM-level manipulation is brittle. Markup/context filtering only handles JSON-serializable options and cannot add JS plugins. Adding every Embla plugin or option directly would increase rtCarousel’s scope and UI complexity.

A small filter-based API keeps the plugin focused while enabling advanced integrations.

Additional context

rtCarousel already exposes a JavaScript filter for slide templates: rtcamp.carouselKit.slideTemplates. Similar filters around Embla initialization would fit the existing extension pattern.

Example plugin usage:

import { addFilter } from '@wordpress/hooks';
import AutoHeight from 'embla-carousel-auto-height';
import ClassNames from 'embla-carousel-class-names';

addFilter(
    'rtcamp.carouselKit.emblaOptions',
    'my-plugin/embla-options',
    (options, { root }) => {
        if (!root.classList.contains('has-advanced-carousel')) {
            return options;
        }

        return {
            ...options,
            duration: 40,
            dragThreshold: 20,
            skipSnaps: true,
        };
    }
);

addFilter(
    'rtcamp.carouselKit.emblaPlugins',
    'my-plugin/embla-plugins',
    (plugins, { root }) => {
        if (!root.classList.contains('has-advanced-carousel')) {
            return plugins;
        }

        return [
            ...plugins,
            AutoHeight(),
            ClassNames(),
        ];
    }
);

Ideally this would be a runtime-only change and would not alter saved block markup, so existing content would remain valid and no block deprecation would be needed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions