Draggable Card Carousel

A touch-friendly draggable carousel with momentum scrolling, cards that snap to center, smooth elastic boundaries, and 3D perspective tilt effects. Modern, sleek, and beautiful.


Draggable Card Carousel


Build a highly interactive, touch-friendly draggable carousel with momentum scrolling and 3D perspective effects. This snippet uses vanilla JavaScript for physics-based movement and CSS perspective for depth.

HTML Structure

The structure consists of a container, a track that holds the cards, and a container for navigation indicators.

<div class="carousel-container">
  <div class="carousel-track">
    <!-- Card 1 -->
    <div class="carousel-card">
      <div class="card-visual visual-gradient-1"></div>
      <div class="card-content">
        <h3>Neon Dreams</h3>
        <p>Experience the vibrant glow of the future.</p>
      </div>
    </div>
    
    <!-- More Cards... -->
    
  </div>
  
  <div class="carousel-indicators">
    <!-- Indicators injected by JS -->
  </div>
</div>

CSS Styling

Key styling includes perspective on the container and transform-style: preserve-3d on the track. Cards are styled with glassmorphism using backdrop-filter.

:root {
  --bg-color: #050505;
  --card-bg: rgba(255, 255, 255, 0.05);
  --gap: 40px;
  --card-width: 320px;
  --card-height: 480px;
}

.carousel-container {
  width: 100%;
  height: 100vh;
  position: relative;
  display: flex;
  align-items: center;
  perspective: 1000px; /* Essential for 3D depth */
}

.carousel-track {
  display: flex;
  gap: var(--gap);
  cursor: grab;
  align-items: center;
  transform-style: preserve-3d; 
  will-change: transform;
}

.carousel-card {
  width: var(--card-width);
  height: var(--card-height);
  flex-shrink: 0;
  border-radius: 24px;
  background: var(--card-bg);
  border: 1px solid rgba(255, 255, 255, 0.1);
  backdrop-filter: blur(10px);
  overflow: hidden;
  transition: box-shadow 0.3s ease;
  user-select: none;
}

JavaScript Implementation

The JavaScript handles:

  1. Drag & Momentum: Tracks mouse/touch movement and applies velocity with friction.
  2. Snap to Center: calculating the nearest card to stop at.
  3. 3D Tilt & Scale: Rotates and scales cards based on their distance from the center of the viewport.
class DraggableCarousel {
  constructor(track, container) {
    this.track = track;
    this.container = container;
    this.cards = Array.from(track.children);
    this.state = {
      currentX: 0,
      targetX: 0,
      isDragging: false,
      startX: 0,
      velocity: 0
    };
    this.init();
  }

  init() {
    // Event listeners setup (start, move, end)
    // ...
    this.animate();
  }

  handleMove(e) {
    if (!this.state.isDragging) return;
    const x = this.getX(e);
    const diff = x - this.state.startX;
    this.state.currentX += diff;
    this.state.targetX = this.state.currentX;
    this.state.velocity = diff;
    this.state.startX = x;
  }

  animate() {
    // Smooth follow logic for drag
    if (!this.state.isDragging) {
       this.state.currentX += (this.state.targetX - this.state.currentX) * 0.1;
    }
    
    // Apply transform to track
    this.track.style.transform = `translateX(${this.state.currentX}px)`;
    
    // 3D Effect for each card
    this.cards.forEach((card, i) => {
       // Calculation of distFromCenter...
       
       const rotateY = (distFromCenter / maxDist) * 45;
       const scale = 1 - Math.abs(distFromCenter / maxDist) * 0.2;
       
       card.style.transform = `perspective(1000px) rotateY(${rotateY}deg) scale(${scale})`;
    });
    
    requestAnimationFrame(this.animate.bind(this));
  }
}