Cara Membuat Draggable Card Slider dengan HTML, CSS, & JavaScript: Panduan Lengkap dari Nol
Slider kartu (card slider) adalah komponen UI penting untuk menampilkan konten seperti testimonial, portofolio, atau produk. Di artikel ini, Anda akan belajar membuat draggable card slider dengan fitur:
- Geser manual menggunakan mouse
- Navigasi panah kiri/kanan
- Scroll infinit tanpa batas
- Autoplay otomatis
- Responsif di semua ukuran layar
Berikut kode lengkap yang bisa langsung Anda implementasikan:
1. Struktur Folder & Persiapan
Buat folder dengan struktur berikut:
📂 draggable-slider/ ├── 📄 index.html ├── 📄 style.css ├── 📄 script.js └── 📂 images/ (6 gambar dengan nama img-1.jpg sampai img-6.jpg)
2. Kode HTML Lengkap
Salin seluruh kode ini ke index.html
:
<!DOCTYPE html> <html lang="id"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Draggable Card Slider | Tutorial Lengkap</title> <link rel="stylesheet" href="style.css"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.3.0/css/all.min.css"> </head> <body> <div class="wrapper"> <i id="left" class="fa-solid fa-angle-left"></i> <ul class="carousel"> <li class="card"> <div class="img"><img src="images/img-1.jpg" alt="Blanche Pearson" draggable="false"></div> <h2>Blanche Pearson</h2> <span>Sales Manager</span> </li> <li class="card"> <div class="img"><img src="images/img-2.jpg" alt="Joenas Brauers" draggable="false"></div> <h2>Joenas Brauers</h2> <span>Web Developer</span> </li> <li class="card"> <div class="img"><img src="images/img-3.jpg" alt="Lariach French" draggable="false"></div> <h2>Lariach French</h2> <span>Online Teacher</span> </li> <li class="card"> <div class="img"><img src="images/img-4.jpg" alt="James Khosravi" draggable="false"></div> <h2>James Khosravi</h2> <span>Freelancer</span> </li> <li class="card"> <div class="img"><img src="images/img-5.jpg" alt="Kristina Zasiadko" draggable="false"></div> <h2>Kristina Zasiadko</h2> <span>Bank Manager</span> </li> <li class="card"> <div class="img"><img src="images/img-6.jpg" alt="Donald Horton" draggable="false"></div> <h2>Donald Horton</h2> <span>App Designer</span> </li> </ul> <i id="right" class="fa-solid fa-angle-right"></i> </div> <script src="script.js"></script> </body> </html>
3. Kode CSS Lengkap
Salin seluruh kode ini ke style.css
:
/* Base Style */ @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600&display=swap'); * { margin: 0; padding: 0; box-sizing: border-box; font-family: "Poppins", sans-serif; } body { display: flex; align-items: center; justify-content: center; min-height: 100vh; padding: 0 35px; background: linear-gradient(to left top, #031A9A, #8B53FF); } /* Wrapper dan Navigasi */ .wrapper { max-width: 1100px; width: 100%; position: relative; } .wrapper i { height: 50px; width: 50px; background: #fff; text-align: center; line-height: 50px; border-radius: 50%; cursor: pointer; position: absolute; top: 50%; font-size: 1.25rem; transform: translateY(-50%); box-shadow: 0 3px 6px rgba(0,0,0,0.23); transition: transform 0.1s linear; } .wrapper i:active { transform: translateY(-50%) scale(0.85); } .wrapper i:first-child { left: -22px; } .wrapper i:last-child { right: -22px; } /* Grid System */ .carousel { display: grid; grid-auto-flow: column; grid-auto-columns: calc((100% / 3) - 12px); gap: 16px; overflow-x: auto; scroll-snap-type: x mandatory; scroll-behavior: smooth; scrollbar-width: none; } .carousel::-webkit-scrollbar { display: none; } .carousel.dragging { scroll-snap-type: none; scroll-behavior: auto; } .carousel.dragging .card { cursor: grab; user-select: none; } .carousel .card { scroll-snap-align: start; height: 342px; list-style: none; background: #fff; border-radius: 8px; padding-bottom: 15px; display: flex; flex-direction: column; align-items: center; justify-content: center; cursor: pointer; } .card .img { background: #8B53FF; width: 148px; height: 148px; border-radius: 50%; display: flex; align-items: center; justify-content: center; } .card .img img { width: 140px; height: 140px; object-fit: cover; border-radius: 50%; border: 4px solid #fff; } .card h2 { font-weight: 500; font-size: 1.56rem; margin: 30px 0 5px; } .card span { color: #6A6D78; font-size: 1.31rem; } /* Responsive Design */ @media screen and (max-width: 900px) { .carousel { grid-auto-columns: calc((100% / 2) - 9px); } } @media screen and (max-width: 600px) { .carousel { grid-auto-columns: 100%; } }
4. Kode JavaScript Lengkap
Salin seluruh kode ini ke script.js
:
const wrapper = document.querySelector(".wrapper"); const carousel = document.querySelector(".carousel"); const firstCardWidth = carousel.querySelector(".card").offsetWidth; const arrowBtns = document.querySelectorAll(".wrapper i"); const carouselChildrens = [...carousel.children]; let isDragging = false, isAutoPlay = true, startX, startScrollLeft, timeoutId; // Hitung jumlah kartu yang tampil const cardPerView = Math.round(carousel.offsetWidth / firstCardWidth); // Duplikasi kartu untuk efek infinite carouselChildrens.slice(-cardPerView).reverse().forEach(card => { carousel.insertAdjacentHTML("afterbegin", card.outerHTML); }); carouselChildrens.slice(0, cardPerView).forEach(card => { carousel.insertAdjacentHTML("beforeend", card.outerHTML); }); // Inisialisasi scroll position carousel.classList.add("no-transition"); carousel.scrollLeft = carousel.offsetWidth; carousel.classList.remove("no-transition"); // Event listener untuk tombol panah arrowBtns.forEach(btn => { btn.addEventListener("click", () => { carousel.scrollLeft += btn.id === "left" ? -firstCardWidth : firstCardWidth; }); }); // Fungsi drag 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"); } // Fungsi infinite scroll 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"); } } // Autoplay const autoPlay = () => { if(window.innerWidth < 800 || !isAutoPlay) return; timeoutId = setTimeout(() => carousel.scrollLeft += firstCardWidth, 2500); } autoPlay(); // Event listeners 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);
5. Penjelasan Fitur Utama
- Infinite Scroll
- Teknik duplikasi kartu di awal dan akhir carousel
- Reset scroll position tanpa animasi saat mencapai ujung
- Drag & Drop
- Hitung pergerakan mouse menggunakan
pageX
- Update
scrollLeft
berdasarkan perbedaan posisi
- Hitung pergerakan mouse menggunakan
- Autoplay
- Geser otomatis setiap 2.5 detik
- Berhenti saat mouse berada di area slider
- Responsive Design
- Grid layout berubah dari 3 → 2 → 1 kolom sesuai lebar layar
- Media query untuk mobile-first approach
Kesimpulan dan Kata Penutup
Membuat draggable card slider dari nol adalah cara efektif untuk memahami konsep fundamental front-end development: manipulasi DOM dengan JavaScript, teknik CSS Grid, dan logika interaksi pengguna. Dengan menyelesaikan proyek ini, Anda telah mempraktikkan:
- Manajemen Scroll: Infinite scroll tanpa library eksternal.
- Drag Interaction: Geser elemen dengan event mouse.
- Responsive Design: Adaptasi layout untuk mobile dan desktop.