Free Before/After Slider Section for ShopifyNo app. Copy, paste, done.
- Online Store 2.0
- No app
- Theme Check: 0 errors
- MIT license
The Stackframes before/after slider is a free Shopify section that stacks two photos and lets shoppers drag a handle to reveal the difference. It suits cleaning products, skincare, restoration and makeovers. It is built on a native range input, so it works with touch, mouse and keyboard, and screen readers announce it. The only script is a few lines.
Live preview with sample content. Once installed, fonts follow your theme and colours are editable in the theme editor.
{%- liquid
assign before = section.settings.before_image
assign after = section.settings.after_image
assign ready = false
if before != blank and after != blank
assign ready = true
endif
assign before_alt = before.alt | default: section.settings.before_label
assign after_alt = after.alt | default: section.settings.after_label
-%}
{%- if ready or request.design_mode -%}
<sf-before-after
class="sf-ba"
style="--sf-ba-pos: {{ section.settings.start_position }}%; --sf-ba-ratio: {{ section.settings.aspect_ratio }}; --sf-ba-handle: {{ section.settings.handle_color }}; --sf-ba-text: {{ section.settings.text_color }}; --sf-ba-bg: {{ section.settings.background_color }}; --sf-ba-pt: {{ section.settings.padding_top }}px; --sf-ba-pb: {{ section.settings.padding_bottom }}px;"
>
<div class="sf-ba__inner">
{%- if section.settings.heading != blank -%}
<h2 class="sf-ba__heading">{{ section.settings.heading | escape }}</h2>
{%- endif -%}
<div class="sf-ba__frame">
<div class="sf-ba__layer">
{%- if after != blank -%}
{{ after | image_url: width: 1800 | image_tag: widths: '600, 900, 1200, 1800', sizes: '(min-width: 1000px) 960px, 100vw', loading: 'lazy', alt: after_alt, class: 'sf-ba__img' }}
{%- else -%}
{{ 'lifestyle-2' | placeholder_svg_tag: 'sf-ba__img sf-ba__placeholder' }}
{%- endif -%}
</div>
<div class="sf-ba__layer sf-ba__layer--before">
{%- if before != blank -%}
{{ before | image_url: width: 1800 | image_tag: widths: '600, 900, 1200, 1800', sizes: '(min-width: 1000px) 960px, 100vw', loading: 'lazy', alt: before_alt, class: 'sf-ba__img' }}
{%- else -%}
{{ 'lifestyle-1' | placeholder_svg_tag: 'sf-ba__img sf-ba__placeholder' }}
{%- endif -%}
</div>
{%- if section.settings.before_label != blank -%}
<span class="sf-ba__label sf-ba__label--before" aria-hidden="true">{{ section.settings.before_label | escape }}</span>
{%- endif -%}
{%- if section.settings.after_label != blank -%}
<span class="sf-ba__label sf-ba__label--after" aria-hidden="true">{{ section.settings.after_label | escape }}</span>
{%- endif -%}
<input class="sf-ba__range" type="range" min="0" max="100" step="1" value="{{ section.settings.start_position }}" aria-label="Slide to compare before and after">
<span class="sf-ba__divider" aria-hidden="true">
<span class="sf-ba__knob">
<svg aria-hidden="true" focusable="false" viewBox="0 0 24 24" width="20" height="20"><path d="M9 7l-5 5 5 5M15 7l5 5-5 5" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>
</span>
</span>
</div>
{%- if ready == false -%}
<p class="sf-ba__empty">Choose a before image and an after image. The section stays hidden on your store until both are set.</p>
{%- endif -%}
</div>
</sf-before-after>
{%- endif -%}
{% stylesheet %}
.sf-ba { display: block; background: var(--sf-ba-bg); color: var(--sf-ba-text); padding: var(--sf-ba-pt) 20px var(--sf-ba-pb); }
.sf-ba__inner { max-width: 960px; margin: 0 auto; }
.sf-ba__heading { margin: 0 0 20px; text-align: center; font-size: clamp(24px, 19px + 1.2vw, 36px); line-height: 1.15; }
.sf-ba__frame { position: relative; overflow: hidden; aspect-ratio: var(--sf-ba-ratio); border-radius: 12px; background: #e5e7eb; user-select: none; }
.sf-ba__layer { position: absolute; inset: 0; }
.sf-ba__layer--before { clip-path: inset(0 calc(100% - var(--sf-ba-pos)) 0 0); }
.sf-ba__img { display: block; width: 100%; height: 100%; object-fit: cover; }
.sf-ba__label { position: absolute; top: 12px; padding: 4px 10px; border-radius: 999px; background: rgba(17, 24, 39, 0.72); color: #fff; font-size: 0.8125em; font-weight: 600; pointer-events: none; }
.sf-ba__label--before { left: 12px; }
.sf-ba__label--after { right: 12px; }
.sf-ba__range { position: absolute; inset: 0; z-index: 2; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: ew-resize; touch-action: pan-y; }
.sf-ba__divider { position: absolute; top: 0; bottom: 0; left: var(--sf-ba-pos); z-index: 1; width: 3px; margin-left: -1.5px; background: var(--sf-ba-handle); pointer-events: none; }
.sf-ba__knob { position: absolute; top: 50%; left: 50%; display: grid; place-items: center; width: 44px; height: 44px; border-radius: 999px; background: var(--sf-ba-handle); color: #111827; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.25); transform: translate(-50%, -50%); }
.sf-ba__range:focus-visible ~ .sf-ba__divider .sf-ba__knob { outline: 3px solid #2563eb; outline-offset: 3px; }
.sf-ba__empty { margin: 12px 0 0; padding: 12px 16px; border: 1px dashed currentColor; border-radius: 8px; text-align: center; font-size: 0.875em; opacity: 0.8; }
{% endstylesheet %}
{% javascript %}
if (!customElements.get('sf-before-after')) {
class SfBeforeAfter extends HTMLElement {
connectedCallback() {
this.onInput = (event) => {
if (!event.target.classList.contains('sf-ba__range')) return;
this.style.setProperty('--sf-ba-pos', event.target.value + '%');
};
this.addEventListener('input', this.onInput);
const range = this.querySelector('.sf-ba__range');
if (range) this.style.setProperty('--sf-ba-pos', range.value + '%');
}
disconnectedCallback() {
this.removeEventListener('input', this.onInput);
}
}
customElements.define('sf-before-after', SfBeforeAfter);
}
{% endjavascript %}
{% schema %}
{
"name": "SF before/after",
"tag": "section",
"class": "sf-ba-section",
"disabled_on": { "groups": ["header", "footer"] },
"settings": [
{ "type": "text", "id": "heading", "label": "Heading", "default": "See the difference" },
{ "type": "image_picker", "id": "before_image", "label": "Before image" },
{ "type": "image_picker", "id": "after_image", "label": "After image", "info": "Use two images with the same framing and size." },
{ "type": "text", "id": "before_label", "label": "Before label", "default": "Before" },
{ "type": "text", "id": "after_label", "label": "After label", "default": "After" },
{ "type": "range", "id": "start_position", "label": "Starting position", "min": 10, "max": 90, "step": 5, "unit": "%", "default": 50 },
{
"type": "select",
"id": "aspect_ratio",
"label": "Shape",
"options": [
{ "value": "1 / 1", "label": "Square" },
{ "value": "4 / 3", "label": "Landscape 4:3" },
{ "value": "3 / 2", "label": "Landscape 3:2" },
{ "value": "16 / 9", "label": "Wide 16:9" },
{ "value": "3 / 4", "label": "Portrait 3:4" }
],
"default": "4 / 3"
},
{ "type": "header", "content": "Colors" },
{ "type": "color", "id": "handle_color", "label": "Handle", "default": "#ffffff" },
{ "type": "color", "id": "text_color", "label": "Text", "default": "#121212" },
{ "type": "color", "id": "background_color", "label": "Background", "default": "#ffffff" },
{ "type": "header", "content": "Spacing" },
{ "type": "range", "id": "padding_top", "label": "Top padding", "min": 0, "max": 100, "step": 4, "unit": "px", "default": 48 },
{ "type": "range", "id": "padding_bottom", "label": "Bottom padding", "min": 0, "max": 100, "step": 4, "unit": "px", "default": 48 }
],
"presets": [{ "name": "SF before/after" }]
}
{% endschema %}
- Drag the handle or use arrow keys to compare
- Native range input — screen readers announce it
- Responsive images served by Shopify's CDN
- Five shapes from square to wide
- Hidden on your store until both images are set
Add the Before/After Slider to your theme
About two minutes. No app, no monthly fee.
Prefer a walkthrough? See the full installation guide.
- STEP 01
Duplicate your theme
In Shopify admin go to Online Store → Themes. Next to your current theme click ⋯ → Duplicate. Make every change on the copy.
- STEP 02
Create the section file
On the copy, click ⋯ → Edit code. In the sections folder click “Add a new section”, choose Liquid, name it sf-before-after-slider and create it. Delete the starter code, paste ours, then click Save.
- STEP 03
Add it to a page
Click Customize, open the template you want, click “Add section” and choose “SF before/after”. Edit the text, blocks and colours in the sidebar, then Save.
- STEP 04
Check it, then publish
Preview on mobile and desktop. When you are happy, publish the duplicate theme.
What you can change in the theme editor
| Setting | Type | Default |
|---|---|---|
| Heading | Text | See the difference |
| Before image | Image | — |
| After imageUse two images with the same framing and size. | Image | — |
| Before label | Text | Before |
| After label | Text | After |
| Starting position | Slider | 50% |
| Shape | Dropdown | Landscape 4:3 |
| Handle | Colour | #ffffff |
| Text | Colour | #121212 |
| Background | Colour | #ffffff |
| Top padding | Slider | 48px |
| Bottom padding | Slider | 48px |
This section is one piece of a custom theme.
We design and build complete Shopify themes around your brand.
Common questions
What images work best?
Two photos taken from the same position with the same crop and size. Any difference in framing shows up as a jump when shoppers drag the handle.
Does it work on phones?
Yes. Shoppers drag the handle with a finger, mouse or arrow keys, and vertical scrolling still works over the slider.
Can I add several comparisons?
Add the section more than once — each one works independently. For a gallery of comparisons in one section, we can build a customised version.
More free sections
Testimonials Carousel
Free testimonials carousel section for Shopify with star ratings, photos and swipeable cards. No autoplay, keyboard friendly, no slider library.
Comparison Table
Free "us vs them" comparison table section for Shopify with check marks, text values and a highlighted column. Accessible HTML table, no app.
Size Chart Popup
Free size chart popup for Shopify product pages: a size guide button that opens an accessible dialog with your measurements table. Liquid code, no app.
All free Shopify sections
Get a Shopify theme built around your brand
Custom sections, a full theme build, or changes to the theme you already have. Tell us what your store needs and we'll scope it with you.
Not affiliated with or endorsed by Shopify Inc. Shopify is a trademark of Shopify Inc.