How to Create A Draggable Card Slider in HTML CSS & JavaScript
Today we will Create A Draggable Card Slider in HTML CSS & JavaScript. Mostly, Sliders have become a crucial part of web design and are used to show images or content in an engaging and interactive way. In this blog post, we will show you how to create a draggable card slider in HTML, CSS, and JavaScript. which can be used to display images, reviews, testimonials, products, user profiles, and other content.
In this tutorial, we will create a draggable card slider that works, we don’t use any external JavaScript libraries such as Owl Carousel or SwiperJs. Instead, we will create the slider from scratch using JavaScript, HTML, and CSS. A Draggable card slider, the user can slide cards by dragging using the left or right arrow. It also includes infinite scrolling and autoplay functionality.
How to Create A Draggable Card Slider in HTML CSS & JavaScript
Example
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>How to Create A Draggable Card Slider in HTML CSS & JavaScript</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.14.0/css/all.min.css">
<link rel="stylesheet" href="styles.css">
<script src="scripts.js" defer></script>
</head>
<body>
<div class="main-wrapper">
<h1 class="text-center">How to Create A Draggable Card Slider in HTML CSS & JavaScript</h1>
<i id="left" class="fa fa-solid fa-angle-left"></i>
<ul class="carousel">
<li class="card">
<div class="img"><img src="images/john-india.jpg" alt="img" draggable="false"></div>
<h2>John India</h2>
<span>Sales Manager</span>
</li>
<li class="card">
<div class="img"><img src="images/mike-us.jpg" alt="img" draggable="false"></div>
<h2>Mike US</h2>
<span>Web Developer</span>
</li>
<li class="card">
<div class="img"><img src="images/lary-us.jpg" alt="img" draggable="false"></div>
<h2>Lary US</h2>
<span>Online Teacher</span>
</li>
<li class="card">
<div class="img"><img src="images/james-canada.jpg" alt="img" draggable="false"></div>
<h2>James Canada</h2>
<span>Freelancer</span>
</li>
<li class="card">
<div class="img"><img src="images/kishan-india.jpg" alt="img" draggable="false"></div>
<h2>Kishan India</h2>
<span>Bank Manager</span>
</li>
<li class="card">
<div class="img"><img src="images/lomas-india.jpg" alt="img" draggable="false"></div>
<h2>Lomas India</h2>
<span>App Designer</span>
</li>
</ul>
<i id="right" class="fa fa-solid fa-angle-right"></i>
</div>
</body>
</html>
styles.css
@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@100;300;400;500;700;900&display=swap');
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Roboto', sans-serif;
}
body {
display: flex;
padding: 0 35px;
align-items: center;
justify-content: center;
min-height: 100vh;
}
.text-center {
text-align: center;
}
.main-wrapper {
max-width: 1100px;
width: 100%;
position: relative;
}
.main-wrapper i {
top: 50%;
height: 50px;
width: 50px;
cursor: pointer;
font-size: 1.25rem;
position: absolute;
text-align: center;
line-height: 50px;
border-radius: 50%;
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.23);
transform: translateY(-50%);
transition: transform 0.1s linear;
}
.main-wrapper i:active {
transform: translateY(-50%) scale(0.85);
}
.main-wrapper i:first-child {
left: -22px;
}
.main-wrapper i:last-child {
right: -22px;
}
.main-wrapper .carousel {
display: grid;
grid-auto-flow: column;
grid-auto-columns: calc((100% / 3) - 12px);
overflow-x: auto;
scroll-snap-type: x mandatory;
gap: 16px;
border-radius: 8px;
scroll-behavior: smooth;
scrollbar-width: none;
}
.carousel::-webkit-scrollbar {
display: none;
}
.carousel.no-transition {
scroll-behavior: auto;
}
.carousel.dragging {
scroll-snap-type: none;
scroll-behavior: auto;
}
.carousel.dragging .card {
cursor: grab;
user-select: none;
}
.carousel :where(.card, .img) {
display: flex;
justify-content: center;
align-items: center;
}
.carousel .card {
scroll-snap-align: start;
height: 342px;
list-style: none;
background: #fff;
cursor: pointer;
padding-bottom: 15px;
flex-direction: column;
border-radius: 8px;
}
.carousel .card .img {
background: #8B53FF;
height: 148px;
width: 148px;
border-radius: 50%;
}
.card .img img {
width: 140px;
height: 140px;
border-radius: 50%;
object-fit: cover;
border: 4px solid #fff;
}
.carousel .card h2 {
font-weight: 500;
font-size: 1.56rem;
margin: 30px 0 5px;
}
.carousel .card span {
color: #6A6D78;
font-size: 1.31rem;
}
@media screen and (max-width: 900px) {
.main-wrapper .carousel {
grid-auto-columns: calc((100% / 2) - 9px);
}
}
@media screen and (max-width: 600px) {
.main-wrapper .carousel {
grid-auto-columns: 100%;
}
}
scripts.js
const wrapper = document.querySelector(".main-wrapper");
const carousel = document.querySelector(".carousel");
const firstCardWidth = carousel.querySelector(".card").offsetWidth;
const arrowBtns = document.querySelectorAll(".main-wrapper i");
const carouselChildrens = [...carousel.children];
let isDragging = false,
isAutoPlay = true,
startX, startScrollLeft, timeoutId;
let cardPerView = Math.round(carousel.offsetWidth / firstCardWidth);
carouselChildrens.slice(-cardPerView).reverse().forEach(card => {
carousel.insertAdjacentHTML("afterbegin", card.outerHTML);
});
carouselChildrens.slice(0, cardPerView).forEach(card => {
carousel.insertAdjacentHTML("beforeend", card.outerHTML);
});
carousel.classList.add("no-transition");
carousel.scrollLeft = carousel.offsetWidth;
carousel.classList.remove("no-transition");
arrowBtns.forEach(btn => {
btn.addEventListener("click", () => {
carousel.scrollLeft += btn.id == "left" ? -firstCardWidth : firstCardWidth;
});
});
const dragStart = (e) => {
isDragging = true;
carousel.classList.add("dragging");
startX = e.pageX;
startScrollLeft = carousel.scrollLeft;
}
const dragging = (e) => {
if (!isDragging) return;
carousel.scrollLeft = startScrollLeft - (e.pageX - startX);
}
const dragStop = () => {
isDragging = false;
carousel.classList.remove("dragging");
}
const infiniteScroll = () => {
if (carousel.scrollLeft === 0) {
carousel.classList.add("no-transition");
carousel.scrollLeft = carousel.scrollWidth - (2 *
carousel.offsetWidth);
carousel.classList.remove("no-transition");
}
else if (Math.ceil(carousel.scrollLeft) === carousel.scrollWidth -
carousel.offsetWidth) {
carousel.classList.add("no-transition");
carousel.scrollLeft = carousel.offsetWidth;
carousel.classList.remove("no-transition");
}
clearTimeout(timeoutId);
if (!wrapper.matches(":hover")) autoPlay();
}
const autoPlay = () => {
if (window.innerWidth < 800 || !isAutoPlay) return;
timeoutId = setTimeout(() => carousel.scrollLeft += firstCardWidth,
2500);
}
autoPlay();
carousel.addEventListener("mousedown", dragStart);
carousel.addEventListener("mousemove", dragging);
document.addEventListener("mouseup", dragStop);
carousel.addEventListener("scroll", infiniteScroll);
wrapper.addEventListener("mouseenter", () => clearTimeout(timeoutId));
wrapper.addEventListener("mouseleave", autoPlay);