HomeCSSCardsCreating a Tinder-Style Swipe Card UI with HTML, CSS, and JavaScript

Creating a Tinder-Style Swipe Card UI with HTML, CSS, and JavaScript

If you’re looking to build an interactive, swipeable card interface similar to Tinder’s iconic design, this tutorial breaks down the core HTML, CSS, and JavaScript required to achieve it. Let’s explore how each part contributes to this slick, modern user experience.

HTML Structure

The HTML is minimal and functional. We define a basic HTML5 structure with a single <div> having the class card-container. This container will dynamically hold the stack of cards that the user can interact with. JavaScript will inject these cards into the container, allowing the logic to remain clean and modular.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Tinder Style Card Swipe</title>
    <link rel="stylesheet" href="style.css" />
  </head>
  <body>
    <div class="card-container" id="cardContainer"></div>
    <script src="script.js"></script>
  </body>
</html>

CSS:

The CSS brings the visual style to life. The body is styled to center the card stack both horizontally and vertically, while hiding overflow to prevent scrollbars from appearing. Each .card is absolutely positioned to stack on top of one another. Cards are given a width, height, border-radius, and large centered text, with soft shadows and smooth transitions that make drag movements look fluid. When a card is hovered or dragged, the transition effects enhance the experience.

Notably, only the top card is truly interactive, thanks to positioning logic in the JavaScript.

body {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100vh;
  background: #f0f0f0;
  overflow: hidden;
}
.card-container {
  position: relative;
  width: 300px;
  height: 400px;
}
.card {
  position: absolute;
  width: 100%;
  height: 100%;
  border-radius: 10px;
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 48px;
  color: rgba(0, 0, 0, 0.3);
  user-select: none;
  font-size: 130px;
  transition: transform 0.3s, opacity 0.3s ease;
}
.card:not(:last-child) {
  top: 5px;
}

JavaScript Functionality:

The JavaScript is the heart of the swipe mechanism. It starts by populating the cardContainer with 10 colorful cards, each numbered and stacked. The swipe logic is handled by mouse and touch event listeners, which track horizontal drag distance (deltaX).

When a user drags a card and releases, the script checks if the movement exceeds a threshold (sensitivity). If so, it animates the card off-screen with a rotation and removes it from the DOM. Otherwise, it resets the card to its original position. This simulates the Tinder-style left/right swipe interactions.

The use of transform, transition, and DOM manipulation enables smooth, responsive animations that feel intuitive across both desktop and mobile devices.

const container = document.getElementById("cardContainer");
let isDragging = false;
let startX = 0;
let currentCard = null;

const cardColors = [
  "#b2df8a",
  "#a6cee1",
  "#1f78b4",
  "#33a02b",
  "#fc9a99",
  "#e21a1c",
  "#fdbe70",
  "#ff7f00",
  "#cab2d6",
  "#6a3d9a",
];
for (let i = 10; i >= 1; i--) {
  const card = document.createElement("div");
  card.className = "card";
  card.style.backgroundColor = cardColors[i - 1];
  cardContent = document.createElement("div");
  cardContent.className = "card-content";
  cardContent.textContent = i;
  card.appendChild(cardContent);
  container.appendChild(card);
}

function getTopCard() {
  return container.querySelector(".card:last-child");
}
container.addEventListener("mousedown", (e) => {
  currentCard = getTopCard();
  if (!currentCard) return;
  isDragging = true;
  startX = e.clientX;
  currentCard.style.transition = "none";
});
container.addEventListener("mousemove", (e) => {
  if (!isDragging || !currentCard) return;
  const deltaX = e.clientX - startX;
  currentCard.style.transform = `translateX{deltaX}px) rotate(${
    deltaX / 10
  }deg)`;
});

container.addEventListener("mouseup", (e) => {
  if (!isDragging || !currentCard) return;
  const deltaX = e.clientX - startX;
  handleSwipe(deltaX);
});
container.addEventListener("touchstart", (e) => {
  currentCard = getTopCard();
  if (!currentCard) return;
  isDragging = true;
  startX = e.touches[0].clientX;
  currentCard.style.transition = "none";
});

container.addEventListener("touchmove", (e) => {
  if (!isDragging || !currentCard) return;
  const deltaX = e.touches[0].clientX - startX;
  currentCard.style.transform = `translateX(${deltaX}px) rotate(${
    deltaX / 10
  }deg)`;
});
container.addEventListener("touchend", (e) => {
  if (!isDragging || !currentCard) return;
  const deltaX = e.changedTouches[0].clientX - startX;
  handleSwipe(deltaX);
});

function handleSwipe(deltaX) {
  const sensitivity = 50;
  if (Math.abs(deltaX) > sensitivity) {
    currentCard.style.transition = "transform 0.4s ease, opacity 0.4s ease";
    currentCard.style.transform = `translateX(${
      deltaX > 0 ? 1000 : -1000
    }px) rotate(${deltaX > 0 ? 45 : -45}deg)`;
    currentCard.style.opacity = 0;
    setTimeout(() => {
      currentCard.remove();
      currentCard = null;
    }, 400);
  } else {
    currentCard.style.transition = "transform 0.3s ease";
    currentCard.style.transform = "translateX(0) rotate(0)";
  }
  isDragging = false;
}

 

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

12 − eleven =

Most Popular