frontend-services/craft-compare

Before/after image comparison slider field for Craft CMS

Maintainers

Package info

github.com/frontend-services/craft-compare

Language:JavaScript

Type:craft-plugin

pkg:composer/frontend-services/craft-compare

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

1.0.0 2026-04-02 13:53 UTC

This package is auto-updated.

Last update: 2026-04-02 13:57:48 UTC


README

Before/after image comparison slider field for Craft CMS 5. Editors pick two assets and configure a draggable divider. It also includes a custom web component for rendering the comparison on the frontend out of the box, with support for responsive images, retina displays, and lazy loading.

Requirements

  • Craft CMS 5.0+
  • PHP 8.1+

Field Setup

Add a Compare field to any field layout. The field settings let you configure:

Setting Description
Allowed Volumes Restrict which asset volumes editors can pick from. Leave empty to allow all.
Default Start Position Initial divider position (0–100). Default: 50.
Default Moving Delay (ms) Drag smoothing in milliseconds (0 = instant). Default: 0.
Default Initial Animation Animate the divider when it first enters the viewport. Default: off.
Default Animation Distance (%) How far (0–50%) the divider swings during the intro animation. Default: 10.

Twig Usage

entry.myField.render()

The simplest way to output the comparison component:

{{ entry.compareField.render() }}

Pass a config array to control image transforms and other options:

{{ entry.compareField.render({
    transforms: {
        0:  { width: 600, height: 384, mode: 'crop', quality: 85 },
        768: { width: 768, height: 512, mode: 'crop', quality: 85 },
        1200: { width: 1200, height: 800, mode: 'crop', quality: 85 },
    },
    retina: true,
    lazy: true,
    class: 'my-compare',
    id: 'hero-compare',
}) }}

Config options

Key Type Default Description
transforms array {} Breakpoint → transform map. Keys are min-width values in px; Craft image transforms as values. Generates <picture>/<source> elements.
retina bool true When true, doubles transform dimensions for a 2x srcset descriptor.
lazy bool true Adds loading="lazy" to <img> elements.
class string '' CSS class added to the <craft-compare> element.
id string '' id attribute added to the <craft-compare> element.

Manual output

Access the raw data model to build your own markup:

{% set compare = entry.compareField %}

{% if compare %}
    <craft-compare
        position="{{ compare.startPosition }}"
        delay="{{ compare.movingDelay }}"
        {% if compare.initialAnimation %}
            animate
            animate-distance="{{ compare.initialAnimationDistance }}"
        {% endif %}
    >
        <img slot="before" src="{{ compare.beforeUrl }}" alt="{{ compare.before.alt }}">
        <img slot="after"  src="{{ compare.afterUrl }}"  alt="{{ compare.after.alt }}">
    </craft-compare>
{% endif %}

Available properties

Property Type Description
before Asset|null The "before" asset element.
after Asset|null The "after" asset element.
divider Asset|null The divider asset element (nullable).
beforeUrl string URL of the before asset.
afterUrl string URL of the after asset.
startPosition int Divider position (0–100).
movingDelay int Drag smoothing in ms.
initialAnimation bool Whether the intro animation is enabled.
initialAnimationDistance int Intro animation swing distance (0–50).

<craft-compare> Web Component

The frontend relies on the <craft-compare> custom element, automatically registered when using render() or when the CompareFieldAsset is registered in the CP.

Attributes

Attribute Type Default Description
position number 50 Initial divider position as a percentage (0–100).
delay number 0 Drag smoothing delay in milliseconds.
animate boolean (presence) Enables the viewport-entry animation.
animate-distance number 10 Swing distance for the intro animation (0–50).

Slots

Slot Description
before <img>, <picture>, or <video> for the "before" state.
after <img>, <picture>, or <video> for the "after" state.
divider Optional element used as the drag handle (SVG <span> or <img>).

GraphQL

The field exposes a CompareFieldData type with the following fields:

query {
    entries(section: "blog") {
        ... on blog_default_Entry {
            compareField {
                startPosition
                movingDelay
                initialAnimation
                initialAnimationDistance
                beforeUrl
                afterUrl
                dividerUrl
                before { id url title }
                after  { id url title }
                divider { id url title }
            }
        }
    }
}