webdevpuneet.com

Wheel-Controlled Carousel — HTML CSS JS Snippet

Wheel-Controlled Carousel · Carousels · Plain HTML, CSS & JS · Live preview

Copy & paste

Source Code

<div class="whc-wrap" id="whcWrap">
  <div class="whc-track" id="whcTrack">
    <div class="whc-slide" style="background:linear-gradient(160deg,#6366f1,#4338ca)">01</div>
    <div class="whc-slide" style="background:linear-gradient(160deg,#0ea5e9,#0369a1)">02</div>
    <div class="whc-slide" style="background:linear-gradient(160deg,#ec4899,#9d174d)">03</div>
    <div class="whc-slide" style="background:linear-gradient(160deg,#10b981,#047857)">04</div>
    <div class="whc-slide" style="background:linear-gradient(160deg,#f59e0b,#b45309)">05</div>
  </div>
  <p class="whc-hint">Scroll your mouse wheel or trackpad over the cards to move horizontally.</p>
</div>

Extend with AI

Take This Snippet Further With AI

The AI prompt for this one is for Patreon supporters ($3 a month, 7 days free), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.

· Become a supporter

What's included

Features

Both a plain mouse wheel (deltaY) and a trackpad horizontal swipe (deltaX) drive the same carousel correctly
preventDefault stops the underlying page from scrolling while the cursor is over the carousel
Explicit passive: false makes that preventDefault call actually effective, not silently ignored
Offset is clamped to real, resize-aware bounds — no scrolling past the first or last card
Smooth CSS transition on every wheel-driven movement, not an abrupt jump
No drag handling needed at all — purely wheel/trackpad-driven navigation

About this UI Snippet

Wheel-Controlled Carousel — Turning Vertical Intent Into Horizontal Motion

Screenshot of the Wheel-Controlled Carousel snippet rendered live

A normal page scroll moves the whole page vertically when your cursor happens to be over a carousel — annoying for a carousel that has its own navigation. This snippet flips that relationship: scrolling *over the carousel itself* (with a real mouse wheel or a trackpad) moves the *carousel* horizontally instead, and e.preventDefault() stops the page underneath from scrolling at the same time.

Reading whichever axis actually has signal

A wheel event carries both deltaY (what a plain vertical mouse wheel reports) and deltaX (what a trackpad's two-finger horizontal swipe reports) — and depending on the input device, only one of them is ever meaningfully non-zero. Rather than picking one axis and ignoring the other, this snippet compares their magnitudes and uses whichever is larger: Math.abs(e.deltaX) > Math.abs(e.deltaY) ? e.deltaX : e.deltaY. That's what makes both a plain vertical mouse wheel *and* a trackpad's horizontal swipe drive the exact same carousel correctly, without needing to detect which device is being used.

passive: false, and why it's required here

Modern browsers default wheel listeners to passive: true for scroll performance — but a passive listener's preventDefault() call is silently ignored, so the page would still scroll underneath. Explicitly opting out with { passive: false } is what makes the preventDefault() call actually take effect, at the cost of the browser no longer being able to assume the listener won't block scrolling — the correct, deliberate trade-off for a carousel that's meant to intercept the gesture entirely.

Step by step

How to Use

  1. 1
    Paste HTML, CSS, and JSFive cards appear in a row; the page underneath does not scroll if you scroll over the cards.
  2. 2
    Scroll a mouse wheel over the cardsThe track moves horizontally, one wheel notch of distance per scroll tick.
  3. 3
    Swipe on a trackpadA horizontal two-finger swipe moves the track the same way, using deltaX instead of deltaY.
  4. 4
    Scroll past either endThe track stops cleanly at its real bounds — it can't scroll past the first or last card.
  5. 5
    Resize the windowThe bounds recalculate so the clamp stays accurate at any container width.

Real-world uses

Common Use Cases

Desktop-first product or portfolio carousels
A natural way to browse horizontal content for users on a mouse or trackpad, with no click-to-advance needed.
Gallery or lookbook browsers
Let visitors flow through images at their own scroll pace, no button-clicking required.
Dashboard widget rails
Browse a horizontal row of cards using the same input gesture already used to scroll the rest of the page.
Timeline or roadmap browsers
Navigate a horizontal timeline naturally with a wheel or trackpad instead of dedicated buttons.

Got questions?

Frequently Asked Questions

The wheel event listener calls e.preventDefault(), and is registered with { passive: false } so that call actually takes effect — without that explicit flag, modern browsers treat wheel listeners as passive by default and silently ignore preventDefault, letting the page scroll anyway.

The movement amount comes directly from the wheel event's own delta value, which varies by device and OS scroll settings — to normalize it, multiply delta by a fixed sensitivity constant before applying it to offset.

Wheel events are a desktop input pattern (mouse wheel, trackpad) — for touch, pair this with drag/swipe handling like the Momentum Drag Carousel snippet, since touch devices don't fire wheel events during a finger swipe.

A trackpad's horizontal two-finger swipe reports its intent primarily through deltaX with little or no deltaY — always reading deltaY would make horizontal trackpad gestures do nothing, so comparing magnitudes lets whichever axis actually has signal drive the carousel.

Wheel-only interaction excludes keyboard and touch users — add Left/Right arrow key handlers that adjust offset by one card width, and ensure any content inside each card remains independently focusable and operable.