Skip to content

Storefront JS ​

Guppy follows the standard Shopware storefront JS pattern: PluginBase classes with a lifecycle, registration with PluginManager, selector-based activation via data-* attributes. This page covers architecture, bundled plugins, configuration, and how to write your own.

Plugin architecture ​

Registration ​

javascript
// New plugins
PluginManager.register('SplideSliderPlugin', SplideSliderPlugin);
PluginManager.register('ProductBoxClickPlugin', ProductBoxClickPlugin);

// Plugin overrides (lazy imports possible)
PluginManager.override('QuantitySelector', () => import('./js/quantity-selector.plugin'));

Initialisation via data-* attributes ​

html
<div data-splide-slider-plugin="true"
     data-splide-slider-plugin-options='{...}'>

Bundled plugins ​

SplideSliderPlugin ​

Modern slider based on Splide.js: replaces Shopware's default Tiny Slider.

Features: better performance, full keyboard navigation, screen-reader support, touch gestures, responsive.

javascript
export default class SplideSliderPlugin extends Plugin {
    static options = {
        splideSnippets: ""
    }

    init() {
        this._mountSlider(this.el, this.options.splideSnippets);
    }

    _mountSlider(element, options) {
        var splideSlider = new Splide(element, {
            i18n: options
        }).mount();

        const splideOptions = Object.getPrototypeOf(splideSlider.options);
        if (splideOptions.autoplay === "pause") {
            splideSlider.Components.Autoplay.play();
        }
    }
}

Usage:

html
<div class="splide" data-splide-slider-plugin="true">
    <div class="splide__track">
        <ul class="splide__list">
            <li class="splide__slide">Slide 1</li>
            <li class="splide__slide">Slide 2</li>
        </ul>
    </div>
</div>

UspBannerPlugin ​

No longer part of the theme. As of Guppy 2.8.0 the USP banner lives in the DmfUspBanner plugin, which registers its own storefront plugin and turns the benefits into a slider through window.DmfSplide once they no longer fit side by side.

ProductBoxClickPlugin ​

Extends the product box with fully clickable cards plus keyboard support.

Features: full-box click target, keyboard support, correct focus management, event delegation.

CustomCheckoutPlugin ​

Improves the checkout experience (validation, progress tracking, auto-save, error handling).

html
<div class="checkout-main" data-custom-checkout-plugin="true">

QuantitySelectorPlugin (override) ​

Extends Shopware's quantity selector: input validation, arrow-key navigation, ARIA labels, smooth animations.

Other plugins ​

PluginPurpose
RemoveExtraH1PluginSEO, removes redundant H1 tags after DOM load.
DeliveryInformationMarginPluginDynamic margin adjustment for delivery information.
SplideSliderGalleryPluginExtended gallery with thumbnail sync and zoom.
CollapseFooterColumnsPlugin (override)Accordion footer on mobile.

Splide configuration ​

All Splide.js options are available.

html
<div class="splide"
     data-splide-slider-plugin="true"
     data-splide-slider-plugin-options='{
       "type": "loop",
       "perPage": 4,
       "perMove": 1,
       "gap": "1rem",
       "pagination": false,
       "arrows": true,
       "autoplay": true,
       "interval": 5000,
       "pauseOnHover": true,
       "breakpoints": {
         "1024": { "perPage": 3 },
         "768": { "perPage": 2 },
         "576": { "perPage": 1 }
       }
     }'>
OptionTypeDefaultDescription
typestringslideslide, loop, fade
perPagenumber1Visible slides
perMovenumber1Slides per move
gapstring0Gap between slides
arrowsbooleantrueNavigation arrows
paginationbooleantruePagination dots
autoplaybooleanfalseAuto play
intervalnumber5000Autoplay interval (ms)
pauseOnHoverbooleantruePause on hover
rewindbooleanfalseRewind to start
speednumber400Animation speed (ms)
easingstringcubic-bezier(0.25, 1, 0.5, 1)Easing function

Events ​

javascript
document.addEventListener('DOMContentLoaded', () => {
    const splideEl = document.querySelector('.splide');
    const splide = splideEl._splide;

    if (splide) {
        splide.on('move', (newIndex, prevIndex) => {
            console.log(`Moved from ${prevIndex} to ${newIndex}`);
        });

        splide.on('mounted', () => console.log('Slider mounted'));
        splide.on('autoplay:play', () => console.log('Autoplay started'));
        splide.on('autoplay:pause', () => console.log('Autoplay paused'));
    }
});

ProductBoxClickPlugin ​

javascript
export default class ProductBoxClickPlugin extends Plugin {
    static options = {
        excludeSelectors: '.btn, .product-action, .wishlist-button, input, select',
        linkSelector: '.product-name a, .product-image-link'
    }

    init() {
        this.el.addEventListener('click', this._onClick.bind(this));
        this.el.addEventListener('keydown', this._onKeydown.bind(this));
    }

    _onClick(event) {
        if (event.target.closest(this.options.excludeSelectors)) {
            return;
        }

        const link = this.el.querySelector(this.options.linkSelector);
        if (link) {
            link.click();
        }
    }

    _onKeydown(event) {
        if (event.key === 'Enter' || event.key === ' ') {
            this._onClick(event);
        }
    }
}

Write your own plugin ​

Plugin template ​

javascript
import Plugin from 'src/plugin-system/plugin.class';

export default class MyCustomPlugin extends Plugin {
    static options = {
        myOption: 'default-value',
        anotherOption: true
    };

    init() {
        this._registerEvents();
    }

    _registerEvents() {
        this.el.addEventListener('click', this._onClick.bind(this));
    }

    _onClick(event) {
        console.log('Clicked!', this.options.myOption);
    }

    destroy() {
        // Cleanup
    }
}

Register the plugin ​

javascript
// main.js
import MyCustomPlugin from './plugins/my-custom-plugin';

window.PluginManager.register('MyCustomPlugin', MyCustomPlugin, '[data-my-custom-plugin]');

Use the plugin ​

html
<div data-my-custom-plugin="true"
     data-my-custom-plugin-options='{"myOption": "custom-value"}'>
    <!-- content -->
</div>

Debugging ​

javascript
// Get a plugin instance
const element = document.querySelector('[data-splide-slider-plugin]');
const pluginInstance = window.PluginManager.getPluginInstanceFromElement(element, 'SplideSliderPlugin');

// Inspect options
console.log(pluginInstance.options);

// All registered plugins
console.log(window.PluginManager.getPluginList());

Common issues ​

ProblemCauseFix
Plugin doesn't loadJS errorCheck the browser console
Slider shows no slideswrong HTML structureVerify Splide classes
Events don't fireplugin not initialisedwait for DOMContentLoaded
Autoplay doesn't workautoplay: "pause" setchange to true
  • Architecture: plugin structure and build output (dist/storefront/js/).
  • Twig Overrides: set data-* attributes correctly from templates.
  • DmfSplideSlider: shared slider component consumed by many custom elements.