Build a 3D CMS Slider in Webflow (Native + Finsweet)

Advanced 44:41 webflowslidercms3dfinsweetinteractions

Build a premium 3D slider in Webflow with the native Slider, a CSS reflection, a Slider Change interaction, then make it CMS-driven with Finsweet.

Key takeaways

  • A native Webflow slider moves by the width of its mask, not its slides — so to show several slides at once you shrink the mask and keep the slides matched to it, and it still advances exactly one slide per click.
  • Webflow quietly assigns sliders a fixed 300px height and hidden z-indexes (mask 1, nav 2, arrows 3 and 4) even when the designer shows "auto" — knowing these invisible defaults saves you from baffling height and layering bugs.
  • The 3D depth is an illusion stacked from four properties on every non-active slide — a Y-axis rotation (with children perspective set on the slide), a sub-1 scale, lower opacity, and reduced saturation — not one single trick.
  • The reflection is pure CSS via `-webkit-box-reflect`, targeted by a `data-reflect` attribute so it attaches to any image regardless of class — but a parent's `overflow: hidden` will clip it unless you give the content real height to breathe.
  • Finsweet's List Slider needs a reset attribute so Webflow reapplies your interactions after the CMS injects the slides — without it the animations bind to elements that didn't exist at load, and the first slide won't show as active.

Video chapters

  1. 00:00 Intro
  2. 01:45 Building the structure of the slider
  3. 18:38 Adding the CSS reflection effect
  4. 22:26 Crafting the Slider Change interaction
  5. 32:00 Building a CMS slider with Finsweet Attributes
  6. 38:39 Adding a hover interaction to the slides
  7. 41:45 Addressing slider responsiveness
  8. 42:50 Outro

You can build a premium 3D slider in Webflow using nothing but the native Slider component, a few lines of CSS, and a single Finsweet attribute set — no heavy libraries, no third-party slider plugin. It starts as a flat, static row of images and ends as an immersive, reflective, depth-rich experience that you can point at a hardcoded set of slides or a CMS collection with the exact same interaction.

What makes this worth the time isn’t the finished look — it’s understanding why each piece works. The native slider hides a handful of defaults that trip people up, depth turns out to be four simple properties stacked together, and moving the whole thing onto the CMS is three attributes once you know the one gotcha. Get the mental model and you can reuse this on portfolios, case-study galleries, or any featured-content section.

How it works

The native slider, demystified. The slider is Webflow’s own component, but a few of its defaults work against you. Even when the designer shows the height as “auto”, Webflow secretly applies a fixed 300px height — so you set it to auto manually. The real trick for showing multiple slides at once lives on the mask, not the slides: the distance a slider travels per click is set by the mask width, not the slide width. Shrink the mask (to 40%) and switch its overflow from hidden to visible, and you see neighbouring slides while still advancing one at a time. Resizing the slides instead would look identical in the designer but jump several slides per click. To keep it clean you set children perspective: 700px on the slide (the foundation for the 3D rotation), make the content wrapper inline-block with centered text so it hugs the image, and cap images at max-height: 70vh. Webflow also assigns hidden z-indexes behind the scenes — mask 1, nav wrapper 2, arrows 3 and 4 — which is why a z-index: 1 overlay can sit above the slides yet still leave the arrows clickable.

Depth is four properties, not one. A non-active slide isn’t styled by any single 3D switch — it’s the sum of four things: a Y-axis rotation (made three-dimensional by that children perspective), a scale just under 1, reduced opacity, and lowered saturation. Together, against a near-black background, they push the neighbours back into a faded, greyish haze and let the active slide read as vivid and forward. A separate absolutely-positioned overlay with a horizontal linear gradient (opaque at the edges, transparent through the middle) fades the row into the background at the left and right for a natural light falloff — with pointer-events: none so it never blocks the hover later.

The reflection is pure CSS. The mirrored-on-glass look comes from -webkit-box-reflect — a WebKit-only property that renders a reflection below the element, offset by a small gap, masked by a gradient so it fades out realistically. The clever part is targeting: instead of a class, the CSS matches a data-reflect attribute, so the same effect drops onto any image regardless of what classes it carries. Two things make or break it. The embed holding the CSS should sit at the very top of the page (given a global-styles class) so it loads immediately, and the reflection — which behaves like an absolutely-positioned element and adds no height of its own — gets clipped by the main container’s overflow: hidden. The fix is to give the content wrapper real height (100vh) so there’s room for the reflection to show beneath a 70vh image.

The Slider Change interaction, then the CMS swap. Motion comes from Webflow’s Slider Change trigger, which only appears in the interactions panel once a slide is selected. It gives you two animations: slide in view (becoming active) and slide out of view (leaving active). You animate the content wrapper from the “non-active” values (rotate 15°, scale 85%, opacity 60%, saturation 50%) to the active values (rotate 0, scale 1, opacity 100%, saturation 100%) with an 800ms ease-in-out expo — the same easing set in the slider settings, so everything feels of a piece. The out animation is just the reverse. The catch that makes it look broken at first: set the trigger to Class, not Element, or only the one slide you built it on animates. Moving to the CMS with Finsweet List Slider reuses all of this — you inject collection items into a single empty slide via two fs-cmsslider-element attributes, and because the slides now share the same class, your interaction already applies. The one gotcha: CMS items load after the interaction binds, so you add fs-cmsslider-reset="true" to make Webflow reapply the interaction to the injected slides. (Side effect worth knowing: after a reset the first slide isn’t animated as “active” on load until you interact once.)

How to use it

  1. Build the structure. Section → container (main-container, 48px horizontal / 64px vertical padding, max-width 1440px) → content wrapper → Slider. On the slider, set height to auto and background to transparent. In its settings, choose ease-in-out expo at 800ms, disable infinite/repeat slides (it fights a multi-slide viewport), and turn off the rounded and number nav labels.

  2. Shrink the mask, match the slides. Give the mask a class, set its width to 40%, margin: 0 auto to center the first slide, and (while building) overflow visible so you can see the neighbours. Give the slides a shared class, set children perspective: 700px, and align them vertically to middle. Make the slide content wrapper display: inline-block with the slide’s text aligned center so it hugs the image. Set the image max-height: 70vh and add a data-reflect attribute (name only — the value is ignored).

  3. Add the falloff overlay. Set the main container to position: relative and add an absolutely-positioned, full-size slider-overlay div with a 90° linear gradient: opaque background at 0% and 100%, transparent at 10% and 90%. Give it z-index: 1 and pointer-events: none. Put overflow: hidden back on the main container to kill horizontal scroll.

  4. Drop in the reflection CSS. Add an Embed containing a <style> block with the -webkit-box-reflect rule targeting [data-reflect] (grab the exact CSS from the cloneable). Give the embed a global-styles class and move it to the very top of the page. Then give the section content wrapper height: 100vh so the reflection has room to render beneath the images.

  5. Build the Slider Change interaction. Select a slide, add a Slider Change interaction. In slide in view, animate the content wrapper’s rotate (Y), scale, opacity, and saturation from the non-active values (15°, 85%, 60%, 50%) to active (0°, 100%, 100%, 100%) at 800ms ease-in-out expo, using “set as initial state” for the start values. Duplicate and reverse it for slide out of view. Crucially, set the trigger to Class so every slide animates.

  6. Add the hover interaction (optional). On the slide content wrapper, add a Mouse hover interaction that animates blur (0 → 3px) and saturation (100% → 85%) on hover in, reversed on hover out — same easing, so it matches the rest.

  7. Make it CMS-driven with Finsweet. Rebuild the same structure with a single empty slide, plus a Collection List (hidden with a global class) bound to your images collection. Add Finsweet’s List Slider script to the page head, then set the attributes from the reference table above: fs-cmsslider-element="slider" on the slider, fs-cmsslider-element="list" on the collection list, and fs-cmsslider-reset="true" on the slider so the interaction reapplies after the items load. See the Finsweet List Slider docs for the current script and syntax.

  8. Handle responsiveness. At tablet, widen the mask to ~60% and drop the container’s horizontal padding; at portrait, set the mask to ~75% and shrink the arrow icons (e.g. 32px → 24px).

Configuration reference

Attribute Values Default What it does
fs-cmsslider-element "slider" on the Slider, "list" on the Collection List Tells Finsweet which element is the native slider and which collection list holds the items to inject as slides.
fs-cmsslider-reset true Reapplies (resets) your Webflow interactions after the CMS items populate the slider, so the Slider Change animation runs on the dynamically added slides.

Resources

Frequently asked questions

Why is my Webflow slider stuck at 300px when the height shows auto?
Webflow assigns sliders a hidden default height of 300px even though the designer displays "auto". Set the height to auto yourself in the style panel so the slider adapts to whatever content sits inside it.
How do I show multiple slides at once in a native Webflow slider?
Reduce the slider mask's width — say 40% — and keep each slide the same width as the mask. The distance the slider travels per click is driven by the mask width, not the slide width, so it still moves one slide at a time.
How do I add a reflection effect to an image in Webflow?
Use an embed with the `-webkit-box-reflect` CSS property inside a style tag, and target your images with a custom attribute like `data-reflect` instead of a class. Give the surrounding wrapper enough height so the mirrored image isn't clipped by overflow.
Can I use native Webflow slider interactions with CMS content?
Yes. Finsweet's List Slider pulls CMS items into a native slider, and once you add a reset attribute Webflow reapplies your Slider Change interaction after the items load — so the same animation works on dynamic content.
Why does my Webflow slider interaction only affect the first slide?
The interaction trigger is set to "Element" rather than "Class". Switch it to Class so the animation runs on every element sharing that slide's class, not just the single slide you attached it to.

← Back to the course

Also part of these courses