Free Web Design Code & Scripts

Card Carousel Using Vanilla JavaScript

Card Carousel Using Vanilla JavaScript
Code Snippet:Card Carousel
Author: NIDAL
Published: 5 months ago
Last Updated: August 20, 2025
Downloads: 241
License: MIT
Edit Code online: View on CodePen
Read More

This tutorial will guide you through building a visually appealing and interactive card carousel using only HTML, CSS, and JavaScript – no external libraries needed! This is a great way to showcase items like team members, products, or testimonials on your website. Learn how to implement this dynamic, user-friendly carousel element.

Step 1: Setting up the HTML Structure

First, we’ll create the basic HTML structure for our carousel. This includes containers for the cards, navigation arrows, and dots for indicating the current position. The data attributes on the cards and dots will be crucial for our JavaScript functionality.

<h1 class="about-title">OUR TEAM</h1>

<div class="carousel-container">
	<button class="nav-arrow left">‹</button>
	<div class="carousel-track">
		<div class="card" data-index="0">
			<img src="https://images.unsplash.com/photo-1573497019940-1c28c88b4f3e?q=80&w=3687&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" alt="Team Member 1">
		</div>
		<div class="card" data-index="1">
			<img src="https://images.unsplash.com/photo-1568602471122-7832951cc4c5?q=80&w=3870&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" alt="Team Member 2">
		</div>
		<div class="card" data-index="2">
			<img src="https://images.unsplash.com/photo-1573496359142-b8d87734a5a2?w=900&auto=format&fit=crop&q=60&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8M3x8cHJvZmVzc2lvbmFsJTIwcGVvcGxlfGVufDB8fDB8fHww" alt="Team Member 3">
		</div>
		<div class="card" data-index="3">
			<img src="https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=900&auto=format&fit=crop&q=60&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8N3x8cHJvZmVzc2lvbmFsJTIwcGVvcGxlfGVufDB8fDB8fHww" alt="Team Member 4">
		</div>
		<div class="card" data-index="4">
			<img src="https://images.unsplash.com/photo-1655249481446-25d575f1c054?w=900&auto=format&fit=crop&q=60&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8Mjh8fHByb2Zlc3Npb25hbCUyMHBlb3BsZXxlbnwwfHwwfHx8MA%3D%3D" alt="Team Member 5">
		</div>
		<div class="card" data-index="5">
			<img src="https://images.unsplash.com/photo-1519085360753-af0119f7cbe7?q=80&w=3687&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" alt="Team Member 6">
		</div>
	</div>
	<button class="nav-arrow right">›</button>
</div>

<div class="member-info">
	<h2 class="member-name">David Kim</h2>
	<p class="member-role">Founder</p>
</div>

<div class="dots">
	<div class="dot active" data-index="0"></div>
	<div class="dot" data-index="1"></div>
	<div class="dot" data-index="2"></div>
	<div class="dot" data-index="3"></div>
	<div class="dot" data-index="4"></div>
	<div class="dot" data-index="5"></div>
</div>

Step 2: Styling with CSS

Next, let’s add some CSS to style our carousel. This section focuses on creating the visual appeal of the carousel, including the card layout, transitions, and responsiveness.

* {
	margin: 0;
	padding: 0;
	box-sizing: border-box;
	font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
}

body {
	min-height: 100vh;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	background-color: #f5f5f5;
	overflow: hidden;
}

.about-title {
	font-size: 7.5rem;
	font-weight: 900;
	text-transform: uppercase;
	letter-spacing: -0.02em;
	position: absolute;
	top: 45px;
	left: 50%;
	transform: translateX(-50%);
	pointer-events: none;
	white-space: nowrap;
	font-family: "Arial Black", "Arial Bold", Arial, sans-serif;
	background: linear-gradient(
		to bottom,
		rgb(8 42 123 / 35%) 30%,
		rgb(255 255 255 / 0%) 76%
	);
	-webkit-background-clip: text;
	background-clip: text;
	color: transparent;
}

.carousel-container {
	width: 100%;
	max-width: 1200px;
	height: 450px;
	position: relative;
	perspective: 1000px;
	margin-top: 80px;
}

.carousel-track {
	width: 100%;
	height: 100%;
	display: flex;
	justify-content: center;
	align-items: center;
	position: relative;
	transform-style: preserve-3d;
	transition: transform 0.8s cubic-bezier(0.25, 0.46, 0.45, 0.94);
}

.card {
	position: absolute;
	width: 280px;
	height: 380px;
	background: white;
	border-radius: 20px;
	overflow: hidden;
	box-shadow: 0 20px 40px rgba(0, 0, 0, 0.15);
	transition: all 0.8s cubic-bezier(0.25, 0.46, 0.45, 0.94);
	cursor: pointer;
}

.card img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	transition: all 0.8s cubic-bezier(0.25, 0.46, 0.45, 0.94);
}

.card.center {
	z-index: 10;
	transform: scale(1.1) translateZ(0);
}

.card.center img {
	filter: none;
}

.card.left-2 {
	z-index: 1;
	transform: translateX(-400px) scale(0.8) translateZ(-300px);
	opacity: 0.7;
}

.card.left-2 img {
	filter: grayscale(100%);
}

.card.left-1 {
	z-index: 5;
	transform: translateX(-200px) scale(0.9) translateZ(-100px);
	opacity: 0.9;
}

.card.left-1 img {
	filter: grayscale(100%);
}

.card.right-1 {
	z-index: 5;
	transform: translateX(200px) scale(0.9) translateZ(-100px);
	opacity: 0.9;
}

.card.right-1 img {
	filter: grayscale(100%);
}

.card.right-2 {
	z-index: 1;
	transform: translateX(400px) scale(0.8) translateZ(-300px);
	opacity: 0.7;
}

.card.right-2 img {
	filter: grayscale(100%);
}

.card.hidden {
	opacity: 0;
	pointer-events: none;
}

.member-info {
	text-align: center;
	margin-top: 40px;
	transition: all 0.5s ease-out;
}

.member-name {
	color: rgb(8, 42, 123);
	font-size: 2.5rem;
	font-weight: 700;
	margin-bottom: 10px;
	position: relative;
	display: inline-block;
}

.member-name::before,
.member-name::after {
	content: "";
	position: absolute;
	top: 100%;
	width: 100px;
	height: 2px;
	background: rgb(8, 42, 123);
}

.member-name::before {
	left: -120px;
}

.member-name::after {
	right: -120px;
}

.member-role {
	color: #848696;
	font-size: 1.5rem;
	font-weight: 500;
	opacity: 0.8;
	text-transform: uppercase;
	letter-spacing: 0.1em;
	padding: 10px 0;
	margin-top: -15px;
	position: relative;
}
.dots {
	display: flex;
	justify-content: center;
	gap: 10px;
	margin-top: 60px;
}

.dot {
	width: 12px;
	height: 12px;
	border-radius: 50%;
	background: rgba(8, 42, 123, 0.2);
	cursor: pointer;
	transition: all 0.3s ease;
}

.dot.active {
	background: rgb(8, 42, 123);
	transform: scale(1.2);
}

.nav-arrow {
	position: absolute;
	top: 50%;
	transform: translateY(-50%);
	background: rgba(8, 42, 123, 0.6);
	color: white;
	width: 40px;
	height: 40px;
	border-radius: 50%;
	display: flex;
	align-items: center;
	justify-content: center;
	cursor: pointer;
	z-index: 20;
	transition: all 0.3s ease;
	font-size: 1.5rem;
	border: none;
	outline: none;
	padding-bottom: 4px;
}

.nav-arrow:hover {
	background: rgba(0, 0, 0, 0.8);
	transform: translateY(-50%) scale(1.1);
}

.nav-arrow.left {
	left: 20px;
	padding-right: 3px;
}

.nav-arrow.right {
	right: 20px;
	padding-left: 3px;
}

@media (max-width: 768px) {
	.about-title {
		font-size: 4.5rem;
	}

	.card {
		width: 200px;
		height: 280px;
	}

	.card.left-2 {
		transform: translateX(-250px) scale(0.8) translateZ(-300px);
	}

	.card.left-1 {
		transform: translateX(-120px) scale(0.9) translateZ(-100px);
	}

	.card.right-1 {
		transform: translateX(120px) scale(0.9) translateZ(-100px);
	}

	.card.right-2 {
		transform: translateX(250px) scale(0.8) translateZ(-300px);
	}

	.member-name {
		font-size: 2rem;
	}

	.member-role {
		font-size: 1.2rem;
	}

	.member-name::before,
	.member-name::after {
		width: 50px;
	}

	.member-name::before {
		left: -70px;
	}

	.member-name::after {
		right: -70px;
	}
}

Step 3: Adding JavaScript Functionality

Now for the fun part – making the carousel interactive! The JavaScript code will handle the transitions, navigation, and updates to the displayed member information.

const teamMembers = [
	{ name: "Emily Kim", role: "Founder" },
	{ name: "Michael Steward", role: "Creative Director" },
	{ name: "Emma Rodriguez", role: "Lead Developer" },
	{ name: "Julia Gimmel", role: "UX Designer" },
	{ name: "Lisa Anderson", role: "Marketing Manager" },
	{ name: "James Wilson", role: "Product Manager" }
];

const cards = document.querySelectorAll(".card");
const dots = document.querySelectorAll(".dot");
const memberName = document.querySelector(".member-name");
const memberRole = document.querySelector(".member-role");
const leftArrow = document.querySelector(".nav-arrow.left");
const rightArrow = document.querySelector(".nav-arrow.right");
let currentIndex = 0;
let isAnimating = false;

function updateCarousel(newIndex) {
	if (isAnimating) return;
	isAnimating = true;

	currentIndex = (newIndex + cards.length) % cards.length;

	cards.forEach((card, i) => {
		const offset = (i - currentIndex + cards.length) % cards.length;

		card.classList.remove(
			"center",
			"left-1",
			"left-2",
			"right-1",
			"right-2",
			"hidden"
		);

		if (offset === 0) {
			card.classList.add("center");
		} else if (offset === 1) {
			card.classList.add("right-1");
		} else if (offset === 2) {
			card.classList.add("right-2");
		} else if (offset === cards.length - 1) {
			card.classList.add("left-1");
		} else if (offset === cards.length - 2) {
			card.classList.add("left-2");
		} else {
			card.classList.add("hidden");
		}
	});

	dots.forEach((dot, i) => {
		dot.classList.toggle("active", i === currentIndex);
	});

	memberName.style.opacity = "0";
	memberRole.style.opacity = "0";

	setTimeout(() => {
		memberName.textContent = teamMembers[currentIndex].name;
		memberRole.textContent = teamMembers[currentIndex].role;
		memberName.style.opacity = "1";
		memberRole.style.opacity = "1";
	}, 300);

	setTimeout(() => {
		isAnimating = false;
	}, 800);
}

leftArrow.addEventListener("click", () => {
	updateCarousel(currentIndex - 1);
});

rightArrow.addEventListener("click", () => {
	updateCarousel(currentIndex + 1);
});

dots.forEach((dot, i) => {
	dot.addEventListener("click", () => {
		updateCarousel(i);
	});
});

cards.forEach((card, i) => {
	card.addEventListener("click", () => {
		updateCarousel(i);
	});
});

document.addEventListener("keydown", (e) => {
	if (e.key === "ArrowLeft") {
		updateCarousel(currentIndex - 1);
	} else if (e.key === "ArrowRight") {
		updateCarousel(currentIndex + 1);
	}
});

let touchStartX = 0;
let touchEndX = 0;

document.addEventListener("touchstart", (e) => {
	touchStartX = e.changedTouches[0].screenX;
});

document.addEventListener("touchend", (e) => {
	touchEndX = e.changedTouches[0].screenX;
	handleSwipe();
});

function handleSwipe() {
	const swipeThreshold = 50;
	const diff = touchStartX - touchEndX;

	if (Math.abs(diff) > swipeThreshold) {
		if (diff > 0) {
			updateCarousel(currentIndex + 1);
		} else {
			updateCarousel(currentIndex - 1);
		}
	}
}

updateCarousel(0);

Conclusion

Congratulations! You’ve successfully created a card carousel using vanilla JavaScript. This technique provides a clean and efficient way to add interactive elements to your web pages. Remember that you can customize this further by adjusting the styling, adding more cards, or enhancing the functionality.

Loading... ...

Loading preview...

Device: Desktop
Dimensions: 1200x800
Lines: 0 Characters: 0 Ln 1, Ch 1

Leave a Comment

About W3Frontend

W3Frontend provides free, open-source web design code and scripts to help developers and designers build faster. Every snippet is reviewed before publishing for quality. Learn more.