frontend-services / craft-compare
Before/after image comparison slider field for Craft CMS
Package info
github.com/frontend-services/craft-compare
Language:JavaScript
Type:craft-plugin
pkg:composer/frontend-services/craft-compare
Requires
- craftcms/cms: ^5.0.0
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 } } } } }