Learn how to create beautiful testimonials using HTML, CSS, and JavaScript with easy steps. Perfect for beginners to boost your website design.
Table of Contents
Testimonials play a key role in building trust on websites. A clean and modern testimonial section can boost the look of your site and increase user confidence. In this blog, we will learn how to create testimonials using HTML, CSS, and JavaScript in a simple way.
This tutorial is perfect for beginners who want to improve their web design skills. We will start from scratch and build a responsive and animated testimonial section.
Prerequisites:
Before we start, make sure you know the basics of:
- HTML (Structure of a webpage)
- CSS (Styling and layout)
- JavaScript (For simple interaction)
Source Code
Step 1 (HTML Code):
To get started, we first need to create a basic HTML file. In this file, we will include the main structure for our testimonials. Here's a detailed explanation of the HTML code:
<!DOCTYPE html>
Declares the document type and version of HTML — here, HTML5. This helps browsers render the page correctly.
<html lang="en">
Starts the HTML document and declares that the content is in English.
<head>
The <head> section contains metadata and resources for the page, like fonts, stylesheets, and title.
Inside the <head>:
<meta charset="UTF-8">
- Sets the character encoding to UTF-8 (supports almost all characters, including symbols and languages).
<meta name="viewport" content="width=device-width, initial-scale=1.0">
- Makes the page responsive by adjusting the layout based on the screen width (important for mobile).
<title>Luxury Testimonials</title>
- Sets the browser tab title.
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
- Optimizes font loading by telling the browser to connect early to Google's font servers.
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap" rel="stylesheet">
- Loads the Poppins font family with multiple weights (used for elegant typography).
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
- Loads Font Awesome icons, which are used in the navigation buttons (left and right arrows).
<link rel="stylesheet" href="styles.css">
- Links to a custom stylesheet named styles.css where your main design is written.
<body>
The body contains the visible content of the web page.
<section class="testimonials-section">
This is the main container for the testimonials area.
Inside the Section:
<div class="section-header animate-in">
<h2>Voices of Distinction</h2>
<p class="delay-1">Esteemed clients share their exceptional experiences with our unparalleled service</p>
</div>
Header of the testimonial section
- animate-in and delay-1 are CSS classes used for entrance animations (e.g., fade-in with delay).
- It includes:
- A heading: "Voices of Distinction"
- A description or subtitle to add elegance and context.
<div class="testimonials-container" id="testimonialsContainer">
</div>
- An empty container where testimonial cards will be dynamically added using JavaScript (script.js handles this).
- Has an id so it can be easily accessed and modified with JS.
<div class="testimonial-nav delay-2">
- A navigation section for testimonials (for sliding or switching between them).
- Uses animation delay class delay-2.
Inside this:
<button class="nav-btn" id="prevBtn">
<i class="fas fa-chevron-left"></i>
</button>
- A previous button with a left arrow icon.
<div class="nav-dots" id="navDots"></div>
- A container for navigation dots to indicate which testimonial is active (handled by JavaScript).
<button class="nav-btn" id="nextBtn">
<i class="fas fa-chevron-right"></i>
</button>
- A next button with a right arrow icon.
<script src="script.js"></script>
- Links a JavaScript file (script.js) that:
- Loads testimonial data
- Handles navigation button clicks
- Animates testimonial transitions
- Adds interactivity to dots
Step 2 (CSS Code):
Once the basic HTML structure of the testimonials is in place, the next step is to add styling to the testimonials using CSS. Here’s a explanation of the CSS code:
1. :root – Custom CSS Variables
These are design tokens used throughout the stylesheet.
:root {
--gold: #d4af37; /* Primary gold color */
--gold-light: #f5e6b3; /* Light gold shade */
--gold-dark: #996515; /* Dark gold shade */
--platinum: #e5e4e2; /* Silver/gray color for stars/dots */
--onyx: #0a0a0a; /* Dark black for text */
--ivory: #fffff0; /* Light ivory for background */
--shadow-sm/md/lg/xl: ... /* Different box-shadow levels */
--transition: ... /* Smooth motion for hover/animation */
--radius-sm/md/lg/xl: ... /* Corner radius for rounded borders */
}
2. Base Reset & Body Styling
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
- Removes default spacing and makes padding and borders part of an element’s total width.
body {
font-family: 'Poppins';
background-color: var(--ivory);
color: var(--onyx);
line-height: 1.6;
}
- Sets smooth, modern text with a neutral background and clear dark text.
3. Testimonials Section Styling
.testimonials-section {
padding: 2rem;
max-width: 1800px;
margin: auto;
background: linear-gradient(...);
}
- Centered section with a light gradient background and padding to add breathing space.
4. Section Header
.section-header {
text-align: center;
}
.section-header h2 {
font-size: 3.5rem;
color: var(--onyx);
position: relative;
}
.section-header h2::after {
content: '';
position: absolute;
bottom: -16px;
width: 120px;
height: 4px;
background: linear-gradient(90deg, var(--gold), var(--gold-dark));
}
- The header has a centered title and an animated gold underline for a luxury feel.
5. Testimonials Container
.testimonials-container {
display: flex;
gap: 2.5rem;
overflow-x: hidden;
}
- Lays out the testimonials side-by-side with scrolling support (controlled with JS).
6. Testimonial Card
.testimonial-card {
background: white;
border-radius: var(--radius-xl);
min-width: 480px;
box-shadow: var(--shadow-xl);
opacity: 0.7;
transform: scale(0.95);
}
.testimonial-card.active {
opacity: 1;
transform: scale(1);
}
.testimonial-card:hover {
transform: translateY(-10px) scale(1.02);
}
- Clean white cards with elegant shadows, rounded edges, and hover animation.
- Active cards are scaled up and more opaque to show they’re selected.
7. Quote Styling
.quote-icon {
font-size: 6rem;
color: var(--gold);
opacity: 0.1;
}
- Adds a large, faint quote icon in the background for decorative flair.
.testimonial-content {
font-size: 1.15rem;
font-weight: 300;
color: rgba(10,10,10,0.8);
}
- Sets body testimonial text with light weight and clear contrast.
8. Client Info
.client-info {
display: flex;
align-items: center;
}
.client-avatar {
width: 80px;
border-radius: 50%;
border: 2px solid var(--gold);
}
.testimonial-card:hover .client-avatar {
transform: scale(1.05);
}
- Displays avatar and name side by side.
- Avatar has a gold border and scales on hover for subtle animation.
9. Star Ratings
.rating {
display: flex;
gap: 0.3rem;
}
.star.filled {
color: var(--gold);
}
- Stars show client rating.
- Filled stars are gold and scale slightly on hover.
10. Navigation Controls (Prev/Next + Dots)
.nav-btn {
border-radius: 50%;
background: white;
font-size: 1.3rem;
}
.nav-btn:hover {
color: white;
transform: translateY(-5px);
}
.nav-btn::before {
background: linear-gradient(...gold...);
}
- Prev/Next buttons are styled as gold-hovering circular buttons with smooth animation.
.dot {
width: 14px;
border-radius: 50%;
background-color: var(--platinum);
}
.dot.active {
transform: scale(1.4);
background: linear-gradient(...gold...);
}
- Small dots indicate current testimonial, with scaling and gold highlight for the active one.
11. Responsive Design (Media Queries)
Gradually adjusts styles for smaller screen sizes:
Breakpoints:
| Max Width | Adjustments |
|---|---|
| 1400px | Shrinks card padding/width slightly |
| 1200px | Reduces section padding, font size |
| 992px | Smaller cards and tighter font |
| 768px | Stack client info vertically, smaller nav buttons |
| 576px | Adjust padding, font, and avatar size for mobile |
:root {
--gold: #d4af37;
--gold-light: #f5e6b3;
--gold-dark: #996515;
--platinum: #e5e4e2;
--onyx: #0a0a0a;
--ivory: #fffff0;
--shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.08);
--shadow-md: 0 4px 12px rgba(0, 0, 0, 0.12);
--shadow-lg: 0 15px 35px rgba(0, 0, 0, 0.15);
--shadow-xl: 0 25px 50px rgba(0, 0, 0, 0.2);
--transition: all 0.5s cubic-bezier(0.22, 1, 0.36, 1);
--transition-fast: all 0.3s ease;
--radius-sm: 8px;
--radius-md: 12px;
--radius-lg: 16px;
--radius-xl: 24px;
}
/* Base Reset */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Poppins', sans-serif;
background-color: var(--ivory);
color: var(--onyx);
line-height: 1.6;
-webkit-font-smoothing: antialiased;
font-weight: 400;
}
/* Luxury Section Styling */
.testimonials-section {
padding: 2rem;
max-width: 1800px;
margin: 0 auto;
position: relative;
overflow: hidden;
background: linear-gradient(
135deg,
rgba(212, 175, 55, 0.03) 0%,
rgba(255, 255, 240, 1) 100%
);
}
.section-header {
text-align: center;
margin-bottom: 2rem;
position: relative;
z-index: 10;
}
.section-header h2 {
font-size: 3.5rem;
font-weight: 600;
margin-bottom: 1.5rem;
color: var(--onyx);
position: relative;
display: inline-block;
letter-spacing: -0.5px;
}
.section-header h2::after {
content: '';
position: absolute;
bottom: -16px;
left: 50%;
transform: translateX(-50%);
width: 120px;
height: 4px;
background: linear-gradient(90deg, var(--gold), var(--gold-dark));
border-radius: 2px;
}
.section-header p {
font-size: 1.25rem;
color: rgba(10, 10, 10, 0.7);
max-width: 700px;
margin: 0 auto;
line-height: 1.8;
font-weight: 300;
}
/* Luxury Testimonials Container */
.testimonials-container {
display: flex;
gap: 2.5rem;
padding: 2rem;
position: relative;
z-index: 5;
overflow-x: hidden;
scroll-behavior: smooth;
}
/* Luxury Testimonial Card */
.testimonial-card {
background: white;
border-radius: var(--radius-xl);
padding: 4rem 3rem;
min-width: 480px;
max-width: 500px;
box-shadow: var(--shadow-xl);
transition: var(--transition);
position: relative;
overflow: hidden;
flex-shrink: 0;
opacity: 0.7;
transform: scale(0.95);
border: 1px solid rgba(229, 228, 226, 0.5);
}
.testimonial-card::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 6px;
background: linear-gradient(90deg, var(--gold), var(--gold-dark));
}
/* .testimonial-card::after {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(
135deg,
rgba(212, 175, 55, 0.03) 0%,
rgba(255, 255, 255, 1) 100%
);
pointer-events: none;
} */
.testimonial-card.active {
opacity: 1;
transform: scale(1);
box-shadow: var(--shadow-xl), 0 0 0 2px var(--gold);
}
.testimonial-card:hover {
transform: translateY(-10px) scale(1.02);
box-shadow: var(--shadow-xl), 0 15px 40px rgba(0, 0, 0, 0.15);
}
.quote-icon {
position: absolute;
top: 2.5rem;
right: 2.5rem;
font-size: 6rem;
color: var(--gold);
opacity: 0.1;
z-index: 0;
}
.testimonial-content {
font-size: 1.15rem;
line-height: 1.9;
color: rgba(10, 10, 10, 0.8);
margin-bottom: 3rem;
position: relative;
z-index: 2;
font-weight: 300;
}
.client-info {
display: flex;
align-items: center;
gap: 1.75rem;
}
.client-avatar {
width: 80px;
height: 80px;
border-radius: 50%;
object-fit: cover;
border: 2px solid var(--gold);
box-shadow: var(--shadow-md);
transition: var(--transition-fast);
}
.testimonial-card:hover .client-avatar {
transform: scale(1.05);
box-shadow: var(--shadow-lg);
border-color: var(--gold-dark);
}
.client-details h4 {
font-size: 1.3rem;
font-weight: 600;
margin-bottom: 0.25rem;
color: var(--onyx);
letter-spacing: -0.2px;
}
.client-details p {
font-size: 0.95rem;
color: rgba(10, 10, 10, 0.6);
margin-bottom: 1rem;
font-weight: 300;
}
.rating {
display: flex;
gap: 0.3rem;
}
.star {
color: var(--platinum);
font-size: 1.1rem;
transition: var(--transition-fast);
}
.star.filled {
color: var(--gold);
}
.testimonial-card:hover .star {
transform: scale(1.3);
}
/* Luxury Navigation Controls */
.testimonial-nav {
display: flex;
justify-content: center;
align-items: center;
gap: 2rem;
margin-top: 4rem;
position: relative;
z-index: 5;
}
.nav-btn {
width: 60px;
height: 60px;
border-radius: 50%;
background: white;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
box-shadow: var(--shadow-md);
transition: var(--transition);
color: var(--onyx);
font-size: 1.3rem;
position: relative;
overflow: hidden;
border: 1px solid rgba(229, 228, 226, 0.8);
}
.nav-btn::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(135deg, var(--gold), var(--gold-dark));
opacity: 0;
transition: var(--transition);
}
.nav-btn:hover {
transform: translateY(-5px);
box-shadow: var(--shadow-lg);
color: white;
}
.nav-btn:hover::before {
opacity: 1;
}
.nav-btn i {
position: relative;
z-index: 2;
}
.nav-dots {
display: flex;
align-items: center;
gap: 1rem;
}
.dot {
width: 14px;
height: 14px;
border-radius: 50%;
background-color: var(--platinum);
cursor: pointer;
transition: var(--transition);
position: relative;
}
.dot::after {
content: '';
position: absolute;
top: -5px;
left: -5px;
right: -5px;
bottom: -5px;
border-radius: 50%;
border: 1px solid transparent;
transition: var(--transition);
}
.dot.active {
transform: scale(1.4);
background: linear-gradient(135deg, var(--gold), var(--gold-dark));
}
.dot.active::after {
border-color: rgba(212, 175, 55, 0.3);
}
/* Responsive Design */
@media (max-width: 1400px) {
.testimonial-card {
min-width: 420px;
padding: 3.5rem 2.5rem;
}
}
@media (max-width: 1200px) {
.testimonials-section {
padding: 8rem 2rem;
}
.section-header h2 {
font-size: 3rem;
}
}
@media (max-width: 992px) {
.testimonial-card {
min-width: 380px;
padding: 3rem 2rem;
}
.section-header h2 {
font-size: 2.75rem;
}
.section-header p {
font-size: 1.15rem;
}
}
@media (max-width: 768px) {
.testimonials-container {
padding: 1rem;
}
.testimonial-card {
min-width: 320px;
padding: 2.5rem 2rem;
}
.section-header h2 {
font-size: 2.5rem;
}
.client-info {
flex-direction: column;
align-items: flex-start;
gap: 1.25rem;
}
.nav-btn {
width: 52px;
height: 52px;
font-size: 1.2rem;
}
}
@media (max-width: 576px) {
.testimonials-section {
padding: 6rem 1.5rem;
}
.testimonial-card {
min-width: 280px;
padding: 2rem 1.5rem;
}
.section-header h2 {
font-size: 2.25rem;
}
.testimonial-content {
font-size: 1.05rem;
}
.client-avatar {
width: 70px;
height: 70px;
}
}
/* Luxury Animations */
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.animate-in {
animation: fadeInUp 0.8s cubic-bezier(0.16, 1, 0.3, 1) forwards;
}
.delay-1 {
animation-delay: 0.2s;
}
.delay-2 {
animation-delay: 0.4s;
} Step 3 (JavaScript Code):
Finally, we need to create a function in JavaScript. Here's a explanation of the JavaScript code:
1. Testimonials Data Array
const testimonials = [ {...}, {...}, ... ];
An array of testimonial objects, where each object includes:
- id: Unique identifier
- quote: Client feedback
- name: Client name
- title: Job or company
- avatar: Client photo URL
- rating: Number of stars (1 to 5)
2. DOM Element References
const testimonialsContainer = document.getElementById('testimonialsContainer');
const navDots = document.getElementById('navDots');
const prevBtn = document.getElementById('prevBtn');
const nextBtn = document.getElementById('nextBtn');
Grabs elements from the HTML:
- The main container to display the testimonial cards
- The dots navigation
- Previous/next buttons
3. Configuration Variables
let currentIndex = 0;
let autoScrollInterval;
const scrollSpeed = 400;
const autoScrollDelay = 10000;
- currentIndex: Index of the currently active testimonial
- autoScrollDelay: Auto-change interval (every 10 seconds)
- scrollSpeed: Not used here, but could be used for speed config
- autoScrollInterval: Used to store the interval reference
4. Initialization
document.addEventListener('DOMContentLoaded', initTestimonials);
When the page loads, it runs initTestimonials(), which:
function initTestimonials() {
renderTestimonials();
renderNavigationDots();
setActiveDot();
startAutoScroll();
setupEventListeners();
}
- Displays all testimonials
- Generates navigation dots
- Starts auto-scrolling
- Adds click, keyboard, and swipe event listeners
5. renderTestimonials()
Builds and injects testimonial cards into the container.
Key parts:
- Sets active class on the current card
- Generates star icons dynamically (based on rating)
- Adds inner HTML structure (quote, avatar, name, title, stars)
- Scrolls to the active card using scrollToCurrentCard()
6. renderNavigationDots()
For each testimonial, create a dot element:
dot.className = `dot ${index === currentIndex ? 'active' : ''}`;
- Adds a click event so that clicking a dot moves to the corresponding testimonial.
7. setActiveDot()
Updates which dot and testimonial card are marked as active.
document.querySelectorAll('.dot').forEach(...)
document.querySelectorAll('.testimonial-card').forEach(...)
- Only one dot/card has the active class at a time for visual highlighting.
8. Navigation Functions
navigateToTestimonial(index)
- Goes directly to the given testimonial
- Updates everything (renderTestimonials(), dots, scroll)
navigatePrev() / navigateNext()
- Moves back or forward (loops at ends)
- Uses modulo % to ensure wrap-around
(currentIndex + 1) % testimonials.length
(currentIndex - 1 + testimonials.length) % testimonials.length
9. scrollToCurrentCard()
Centers the active card in the view:
container.scrollTo({
left: card.offsetLeft - container.offsetWidth / 2 + cardWidth / 2,
behavior: 'smooth',
});
- Makes the scrolling experience smooth and professional.
10. Auto-scroll Logic
startAutoScroll()
Starts a timer to auto-switch to the next testimonial.
resetAutoScroll()
Stops and restarts the timer (used after user interaction).
11. setupEventListeners()
Adds interactive controls for better UX:
Button Clicks
prevBtn.addEventListener('click', navigatePrev);
nextBtn.addEventListener('click', navigateNext);
Pause on Hover
testimonialsContainer.addEventListener('mouseenter', ...);
testimonialsContainer.addEventListener('mouseleave', ...);
- Hovering pauses auto-scroll.
- Leaving resumes it.
Keyboard Controls
document.addEventListener('keydown', (e) => {
if (e.key === 'ArrowLeft') ...
});
- Use the arrow keys for navigation.
Touch/Swipe Events
Tracks touch start and end position to detect left/right swipes:
- touchStartX = e.changedTouches[0].screenX;
- ...
- if (touchEndX < touchStartX - threshold) navigateNext();
const testimonials = [
{
id: 1,
quote:
'The epitome of excellence in service delivery. Their attention to detail and commitment to perfection mirrors our own standards at Rothschild & Co. The strategic insights provided have been invaluable to our private wealth division.',
name: 'Eleanor Van der Linden',
title: 'Managing Director, Rothschild & Co',
avatar:
'https://images.unsplash.com/photo-1573497019940-1c28c88b4f3e?w=200&h=200&fit=crop&crop=faces',
rating: 5
},
{
id: 2,
quote:
'Working with their team has been nothing short of transformative for our luxury hospitality group. They understand the nuances of serving discerning clientele at the highest level. The results have exceeded our most ambitious projections.',
name: 'Alexander Laurent',
title: 'CEO, Auberge Resorts Collection',
avatar:
'https://images.unsplash.com/photo-1560250097-0b93528c311a?w=200&h=200&fit=crop&crop=faces',
rating: 5
},
{
id: 3,
quote:
'In the world of haute horlogerie, precision and craftsmanship are paramount. Their approach to digital transformation for our brand maintained these values while bringing us into the modern era without compromising our heritage.',
name: 'Claire Beaumont',
title: 'Digital Director, Patek Philippe',
avatar:
'https://images.unsplash.com/photo-1580489944761-15a19d654956?w=200&h=200&fit=crop&crop=faces',
rating: 5
},
{
id: 4,
quote:
'The discretion and sophistication of their service matches what we expect from our most exclusive properties. Their team operates with the same level of professionalism we demand from our staff at The Ritz Paris.',
name: 'Henri Delacroix',
title: 'General Manager, The Ritz Paris',
avatar:
'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=200&h=200&fit=crop&crop=faces',
rating: 5
},
{
id: 5,
quote:
'As a family office managing ultra-high-net-worth individuals, we require partners who understand the need for absolute confidentiality alongside flawless execution. They have consistently delivered beyond our expectations.',
name: 'Victoria Kensington',
title: 'Principal, Windsor Family Office',
avatar:
'https://images.unsplash.com/photo-1619895862022-09114b41f16f?w=200&h=200&fit=crop&crop=faces',
rating: 5
},
];
// DOM Elements
const testimonialsContainer = document.getElementById('testimonialsContainer');
const navDots = document.getElementById('navDots');
const prevBtn = document.getElementById('prevBtn');
const nextBtn = document.getElementById('nextBtn');
// Configuration
let currentIndex = 0;
let autoScrollInterval;
const scrollSpeed = 400;
const autoScrollDelay = 10000; // 10 seconds
// Initialize
function initTestimonials() {
renderTestimonials();
renderNavigationDots();
setActiveDot();
startAutoScroll();
setupEventListeners();
}
// Render Testimonials
function renderTestimonials() {
testimonialsContainer.innerHTML = '';
testimonials.forEach((testimonial, index) => {
const testimonialElement = document.createElement('div');
testimonialElement.className = `testimonial-card ${
index === currentIndex ? 'active' : ''
}`;
testimonialElement.dataset.index = index;
// Generate star rating
const stars = Array(5)
.fill(0)
.map(
(_, i) =>
`<i class="star ${
i < testimonial.rating ? 'filled fas fa-star' : 'far fa-star'
}"></i>`
)
.join('');
testimonialElement.innerHTML = `
<div class="quote-icon">
<svg width="80" height="80" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7 12C7 14.7614 9.23858 17 12 17C14.7614 17 17 14.7614 17 12C17 9.23858 14.7614 7 12 7V3C16.4183 3 20 6.58172 20 11C20 15.4183 16.4183 19 12 19C7.58172 19 4 15.4183 4 11H7Z" fill="currentColor"/>
</svg>
</div>
<p class="testimonial-content">${testimonial.quote}</p>
<div class="client-info">
<img src="${testimonial.avatar}" alt="${
testimonial.name
}" class="client-avatar">
<div class="client-details">
<h4>${testimonial.name}</h4>
<p>${testimonial.title}</p>
<div class="rating">${stars}</div>
</div>
</div>
`;
testimonialsContainer.appendChild(testimonialElement);
});
// Center the active card
scrollToCurrentCard();
}
// Render Navigation Dots
function renderNavigationDots() {
navDots.innerHTML = '';
testimonials.forEach((_, index) => {
const dot = document.createElement('div');
dot.className = `dot ${index === currentIndex ? 'active' : ''}`;
dot.dataset.index = index;
dot.addEventListener('click', () => {
navigateToTestimonial(index);
});
navDots.appendChild(dot);
});
}
// Set Active Dot
function setActiveDot() {
document.querySelectorAll('.dot').forEach((dot, index) => {
if (index === currentIndex) {
dot.classList.add('active');
} else {
dot.classList.remove('active');
}
});
document.querySelectorAll('.testimonial-card').forEach((card, index) => {
if (index === currentIndex) {
card.classList.add('active');
} else {
card.classList.remove('active');
}
});
}
// Navigation Functions
function navigateToTestimonial(index) {
currentIndex = index;
renderTestimonials();
setActiveDot();
resetAutoScroll();
}
function navigatePrev() {
currentIndex = (currentIndex - 1 + testimonials.length) % testimonials.length;
renderTestimonials();
setActiveDot();
resetAutoScroll();
}
function navigateNext() {
currentIndex = (currentIndex + 1) % testimonials.length;
renderTestimonials();
setActiveDot();
resetAutoScroll();
}
// Smooth scroll to current card
function scrollToCurrentCard() {
const cards = document.querySelectorAll('.testimonial-card');
if (cards[currentIndex]) {
const card = cards[currentIndex];
const container = testimonialsContainer;
const cardWidth = card.offsetWidth;
const scrollPosition =
card.offsetLeft - container.offsetWidth / 2 + cardWidth / 2;
container.scrollTo({
left: scrollPosition,
behavior: 'smooth',
});
}
}
// Auto-scroll functionality
function startAutoScroll() {
autoScrollInterval = setInterval(navigateNext, autoScrollDelay);
}
function resetAutoScroll() {
clearInterval(autoScrollInterval);
startAutoScroll();
}
// Event Listeners
function setupEventListeners() {
prevBtn.addEventListener('click', navigatePrev);
nextBtn.addEventListener('click', navigateNext);
// Pause auto-scroll on hover
testimonialsContainer.addEventListener('mouseenter', () => {
clearInterval(autoScrollInterval);
});
testimonialsContainer.addEventListener('mouseleave', () => {
resetAutoScroll();
});
// Keyboard navigation
document.addEventListener('keydown', (e) => {
if (e.key === 'ArrowLeft') {
navigatePrev();
} else if (e.key === 'ArrowRight') {
navigateNext();
}
});
// Swipe for touch devices
let touchStartX = 0;
let touchEndX = 0;
testimonialsContainer.addEventListener(
'touchstart',
(e) => {
touchStartX = e.changedTouches[0].screenX;
},
{ passive: true }
);
testimonialsContainer.addEventListener(
'touchend',
(e) => {
touchEndX = e.changedTouches[0].screenX;
handleSwipe();
},
{ passive: true }
);
function handleSwipe() {
const threshold = 50;
if (touchEndX < touchStartX - threshold) {
navigateNext();
} else if (touchEndX > touchStartX + threshold) {
navigatePrev();
}
}
}
// Initialize the component
document.addEventListener('DOMContentLoaded', initTestimonials);Final Output:
Conclusion:
You’ve just learned how to create a simple, stylish testimonial section using HTML, CSS, and JavaScript. This section will make your site look more professional and build more trust with your visitors.
Key Benefits:
- Clean and modern design
- Auto-switching testimonials
- Fully responsive
- Easy to customize
Keep practicing and feel free to improve the design or add animation using CSS transitions or libraries like GSAP for advanced effects.
That’s a wrap!
I hope you enjoyed this post. Now, with these examples, you can create your own amazing page.
Did you like it? Let me know in the comments below 🔥 and you can support me by buying me a coffee
And don’t forget to sign up to our email newsletter so you can get useful content like this sent right to your inbox!
Thanks!
Faraz 😊


