<div class="testimonial-container">
<div class="testimonial-header">
<h1 class="testimonial-title">What Our Customers Say</h1>
<p class="testimonial-subtitle">Real feedback from our valued customers</p>
</div>
<div class="testimonial-slider" id="testimonialSlider">
<div class="testimonial-track" id="testimonialTrack">
<!-- Testimonial 1 -->
<div class="testimonial-slide active">
<div class="testimonial-content">
<div class="testimonial-quote">
<svg class="quote-icon" viewBox="0 0 24 24" fill="currentColor">
<path d="M14,17H17L19,13V7H13V13H16M6,17H9L11,13V7H5V13H8L6,17Z" />
</svg>
<p class="testimonial-text">
"This product has completely transformed our workflow. The team's productivity has increased by 300% since we started using it. Absolutely incredible!"
</p>
</div>
<div class="testimonial-rating">
<div class="stars">
<span class="star filled">β
</span>
<span class="star filled">β
</span>
<span class="star filled">β
</span>
<span class="star filled">β
</span>
<span class="star filled">β
</span>
</div>
<span class="rating-text">5.0 out of 5</span>
</div>
<div class="testimonial-author">
<div class="author-avatar">
<img src="https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=80&h=80&fit=crop&crop=face" alt="Sarah Johnson" loading="lazy">
</div>
<div class="author-info">
<h3 class="author-name">Sarah Johnson</h3>
<p class="author-title">CEO, TechCorp</p>
<p class="author-company">San Francisco, CA</p>
</div>
</div>
</div>
</div>
<!-- Testimonial 2 -->
<div class="testimonial-slide">
<div class="testimonial-content">
<div class="testimonial-quote">
<svg class="quote-icon" viewBox="0 0 24 24" fill="currentColor">
<path d="M14,17H17L19,13V7H13V13H16M6,17H9L11,13V7H5V13H8L6,17Z" />
</svg>
<p class="testimonial-text">
"Outstanding customer service and an amazing product. The support team went above and beyond to help us integrate this into our existing systems."
</p>
</div>
<div class="testimonial-rating">
<div class="stars">
<span class="star filled">β
</span>
<span class="star filled">β
</span>
<span class="star filled">β
</span>
<span class="star filled">β
</span>
<span class="star filled">β
</span>
</div>
<span class="rating-text">5.0 out of 5</span>
</div>
<div class="testimonial-author">
<div class="author-avatar">
<img src="https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=80&h=80&fit=crop&crop=face" alt="Michael Chen" loading="lazy">
</div>
<div class="author-info">
<h3 class="author-name">Michael Chen</h3>
<p class="author-title">CTO, InnovateLab</p>
<p class="author-company">New York, NY</p>
</div>
</div>
</div>
</div>
<!-- Testimonial 3 -->
<div class="testimonial-slide">
<div class="testimonial-content">
<div class="testimonial-quote">
<svg class="quote-icon" viewBox="0 0 24 24" fill="currentColor">
<path d="M14,17H17L19,13V7H13V13H16M6,17H9L11,13V7H5V13H8L6,17Z" />
</svg>
<p class="testimonial-text">
"The ROI we've seen from this solution is remarkable. It paid for itself within the first month and continues to deliver exceptional value."
</p>
</div>
<div class="testimonial-rating">
<div class="stars">
<span class="star filled">β
</span>
<span class="star filled">β
</span>
<span class="star filled">β
</span>
<span class="star filled">β
</span>
<span class="star half">β
</span>
</div>
<span class="rating-text">4.5 out of 5</span>
</div>
<div class="testimonial-author">
<div class="author-avatar">
<img src="https://images.unsplash.com/photo-1494790108755-2616c6d4e6e8?w=80&h=80&fit=crop&crop=face" alt="Emily Rodriguez" loading="lazy">
</div>
<div class="author-info">
<h3 class="author-name">Emily Rodriguez</h3>
<p class="author-title">Marketing Director, GrowthCo</p>
<p class="author-company">Austin, TX</p>
</div>
</div>
</div>
</div>
<!-- Testimonial 4 -->
<div class="testimonial-slide">
<div class="testimonial-content">
<div class="testimonial-quote">
<svg class="quote-icon" viewBox="0 0 24 24" fill="currentColor">
<path d="M14,17H17L19,13V7H13V13H16M6,17H9L11,13V7H5V13H8L6,17Z" />
</svg>
<p class="testimonial-text">
"User-friendly interface and powerful features. Our team was up and running in no time. Highly recommend to anyone looking for a reliable solution."
</p>
</div>
<div class="testimonial-rating">
<div class="stars">
<span class="star filled">β
</span>
<span class="star filled">β
</span>
<span class="star filled">β
</span>
<span class="star filled">β
</span>
<span class="star filled">β
</span>
</div>
<span class="rating-text">5.0 out of 5</span>
</div>
<div class="testimonial-author">
<div class="author-avatar">
<img src="https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=80&h=80&fit=crop&crop=face" alt="David Kim" loading="lazy">
</div>
<div class="author-info">
<h3 class="author-name">David Kim</h3>
<p class="author-title">Operations Manager, ScaleTech</p>
<p class="author-company">Seattle, WA</p>
</div>
</div>
</div>
</div>
</div>
<!-- Navigation Controls -->
<div class="testimonial-controls">
<button class="control-btn prev-btn" id="prevBtn">
<svg viewBox="0 0 24 24" fill="currentColor">
<path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"/>
</svg>
</button>
<div class="testimonial-dots" id="testimonialDots">
<button class="dot active" data-slide="0"></button>
<button class="dot" data-slide="1"></button>
<button class="dot" data-slide="2"></button>
<button class="dot" data-slide="3"></button>
</div>
<button class="control-btn next-btn" id="nextBtn">
<svg viewBox="0 0 24 24" fill="currentColor">
<path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"/>
</svg>
</button>
</div>
<!-- Auto-play Toggle -->
<div class="autoplay-controls">
<button class="autoplay-btn" id="autoplayBtn">
<svg class="play-icon" viewBox="0 0 24 24" fill="currentColor">
<path d="M8 5v14l11-7z"/>
</svg>
<svg class="pause-icon" viewBox="0 0 24 24" fill="currentColor" style="display: none;">
<path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"/>
</svg>
<span class="autoplay-text">Auto-play</span>
</button>
</div>
</div>
<!-- Statistics -->
<div class="testimonial-stats">
<div class="stat-item">
<div class="stat-number">4.8</div>
<div class="stat-label">Average Rating</div>
</div>
<div class="stat-item">
<div class="stat-number">1,200+</div>
<div class="stat-label">Happy Customers</div>
</div>
<div class="stat-item">
<div class="stat-number">99%</div>
<div class="stat-label">Satisfaction Rate</div>
</div>
</div>
</div>
.testimonial-container {
max-width: 1000px;
margin: 0 auto;
padding: 48px 24px;
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
}
.testimonial-header {
text-align: center;
margin-bottom: 48px;
}
.testimonial-title {
font-size: 48px;
font-weight: 700;
color: #1a202c;
margin: 0 0 16px 0;
background: linear-gradient(135deg, #667eea, #764ba2);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.testimonial-subtitle {
font-size: 18px;
color: #6b7280;
margin: 0;
font-weight: 400;
}
/* Slider Container */
.testimonial-slider {
position: relative;
background: white;
border-radius: 24px;
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
overflow: hidden;
margin-bottom: 48px;
}
.testimonial-track {
display: flex;
transition: transform 0.6s cubic-bezier(0.4, 0, 0.2, 1);
}
.testimonial-slide {
min-width: 100%;
padding: 48px;
opacity: 0;
transition: opacity 0.6s ease;
}
.testimonial-slide.active {
opacity: 1;
}
.testimonial-content {
max-width: 800px;
margin: 0 auto;
text-align: center;
}
/* Quote Section */
.testimonial-quote {
position: relative;
margin-bottom: 32px;
}
.quote-icon {
width: 48px;
height: 48px;
color: #667eea;
margin-bottom: 24px;
opacity: 0.3;
}
.testimonial-text {
font-size: 24px;
line-height: 1.6;
color: #2d3748;
margin: 0;
font-weight: 400;
font-style: italic;
position: relative;
}
/* Rating Section */
.testimonial-rating {
display: flex;
align-items: center;
justify-content: center;
gap: 16px;
margin-bottom: 32px;
}
.stars {
display: flex;
gap: 4px;
}
.star {
font-size: 20px;
color: #e2e8f0;
transition: color 0.3s ease;
}
.star.filled {
color: #fbbf24;
}
.star.half {
background: linear-gradient(90deg, #fbbf24 50%, #e2e8f0 50%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.rating-text {
font-size: 14px;
color: #6b7280;
font-weight: 500;
}
/* Author Section */
.testimonial-author {
display: flex;
align-items: center;
justify-content: center;
gap: 20px;
}
.author-avatar {
position: relative;
}
.author-avatar img {
width: 80px;
height: 80px;
border-radius: 50%;
object-fit: cover;
border: 4px solid #f7fafc;
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1);
}
.author-info {
text-align: left;
}
.author-name {
font-size: 18px;
font-weight: 600;
color: #1a202c;
margin: 0 0 4px 0;
}
.author-title {
font-size: 14px;
color: #667eea;
margin: 0 0 2px 0;
font-weight: 500;
}
.author-company {
font-size: 12px;
color: #9ca3af;
margin: 0;
}
/* Controls */
.testimonial-controls {
display: flex;
align-items: center;
justify-content: center;
gap: 24px;
padding: 24px;
background: #f8fafc;
}
.control-btn {
width: 48px;
height: 48px;
border: 2px solid #e2e8f0;
background: white;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: all 0.3s ease;
color: #4a5568;
}
.control-btn:hover {
border-color: #667eea;
color: #667eea;
transform: scale(1.05);
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.15);
}
.control-btn:disabled {
opacity: 0.5;
cursor: not-allowed;
transform: none;
}
.control-btn svg {
width: 20px;
height: 20px;
}
/* Dots Navigation */
.testimonial-dots {
display: flex;
gap: 12px;
}
.dot {
width: 12px;
height: 12px;
border-radius: 50%;
border: none;
background: #cbd5e0;
cursor: pointer;
transition: all 0.3s ease;
position: relative;
}
.dot:hover {
background: #a0aec0;
transform: scale(1.2);
}
.dot.active {
background: #667eea;
transform: scale(1.3);
}
.dot.active::after {
content: '';
position: absolute;
top: -4px;
left: -4px;
right: -4px;
bottom: -4px;
border: 2px solid #667eea;
border-radius: 50%;
opacity: 0.3;
}
/* Auto-play Controls */
.autoplay-controls {
display: flex;
justify-content: center;
padding: 16px 24px;
background: #f8fafc;
border-top: 1px solid #e2e8f0;
}
.autoplay-btn {
display: flex;
align-items: center;
gap: 8px;
padding: 8px 16px;
background: transparent;
border: 1px solid #e2e8f0;
border-radius: 20px;
color: #4a5568;
cursor: pointer;
transition: all 0.3s ease;
font-size: 14px;
}
.autoplay-btn:hover {
border-color: #667eea;
color: #667eea;
}
.autoplay-btn.active {
background: #667eea;
border-color: #667eea;
color: white;
}
.autoplay-btn svg {
width: 16px;
height: 16px;
}
/* Statistics */
.testimonial-stats {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 32px;
text-align: center;
}
.stat-item {
padding: 24px;
background: white;
border-radius: 16px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
transition: transform 0.3s ease;
}
.stat-item:hover {
transform: translateY(-4px);
}
.stat-number {
font-size: 36px;
font-weight: 700;
color: #667eea;
margin-bottom: 8px;
}
.stat-label {
font-size: 14px;
color: #6b7280;
font-weight: 500;
}
/* Animations */
@keyframes slideIn {
from {
opacity: 0;
transform: translateX(30px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.testimonial-slide.active .testimonial-content {
animation: slideIn 0.6s ease;
}
.stat-item {
animation: fadeIn 0.6s ease;
}
/* Responsive Design */
@media (max-width: 768px) {
.testimonial-container {
padding: 24px 16px;
}
.testimonial-title {
font-size: 32px;
}
.testimonial-subtitle {
font-size: 16px;
}
.testimonial-slide {
padding: 32px 24px;
}
.testimonial-text {
font-size: 18px;
}
.testimonial-author {
flex-direction: column;
gap: 16px;
}
.author-info {
text-align: center;
}
.author-avatar img {
width: 60px;
height: 60px;
}
.testimonial-controls {
gap: 16px;
padding: 16px;
}
.control-btn {
width: 40px;
height: 40px;
}
.control-btn svg {
width: 16px;
height: 16px;
}
.testimonial-stats {
grid-template-columns: 1fr;
gap: 16px;
}
.stat-item {
padding: 16px;
}
.stat-number {
font-size: 28px;
}
}
@media (max-width: 480px) {
.testimonial-slide {
padding: 24px 16px;
}
.testimonial-text {
font-size: 16px;
}
.quote-icon {
width: 32px;
height: 32px;
}
.testimonial-controls {
flex-direction: column;
gap: 16px;
}
.control-btn {
width: 36px;
height: 36px;
}
.testimonial-dots {
order: -1;
}
}
document.addEventListener('DOMContentLoaded', () => {
const slider = document.getElementById('testimonialSlider');
const track = document.getElementById('testimonialTrack');
const slides = document.querySelectorAll('.testimonial-slide');
const dots = document.querySelectorAll('.dot');
const prevBtn = document.getElementById('prevBtn');
const nextBtn = document.getElementById('nextBtn');
const autoplayBtn = document.getElementById('autoplayBtn');
const playIcon = autoplayBtn.querySelector('.play-icon');
const pauseIcon = autoplayBtn.querySelector('.pause-icon');
const autoplayText = autoplayBtn.querySelector('.autoplay-text');
let currentSlide = 0;
let isAutoplay = true;
let autoplayInterval;
const autoplayDelay = 5000; // 5 seconds
// Initialize slider
function initSlider() {
updateSlider();
startAutoplay();
// Add intersection observer for animations
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.style.animationDelay = '0s';
}
});
});
document.querySelectorAll('.stat-item').forEach(item => {
observer.observe(item);
});
}
// Update slider position and active states
function updateSlider() {
// Update track position
track.style.transform = `translateX(-${currentSlide * 100}%)`;
// Update slide active states
slides.forEach((slide, index) => {
slide.classList.toggle('active', index === currentSlide);
});
// Update dots
dots.forEach((dot, index) => {
dot.classList.toggle('active', index === currentSlide);
});
// Update navigation buttons
prevBtn.disabled = currentSlide === 0;
nextBtn.disabled = currentSlide === slides.length - 1;
}
// Go to specific slide
function goToSlide(index) {
if (index >= 0 && index < slides.length) {
currentSlide = index;
updateSlider();
// Reset autoplay timer
if (isAutoplay) {
stopAutoplay();
startAutoplay();
}
}
}
// Go to next slide
function nextSlide() {
const nextIndex = currentSlide + 1;
if (nextIndex < slides.length) {
goToSlide(nextIndex);
} else if (isAutoplay) {
// Loop back to first slide in autoplay mode
goToSlide(0);
}
}
// Go to previous slide
function prevSlide() {
const prevIndex = currentSlide - 1;
if (prevIndex >= 0) {
goToSlide(prevIndex);
}
}
// Start autoplay
function startAutoplay() {
if (isAutoplay) {
autoplayInterval = setInterval(() => {
nextSlide();
}, autoplayDelay);
autoplayBtn.classList.add('active');
playIcon.style.display = 'none';
pauseIcon.style.display = 'block';
autoplayText.textContent = 'Auto-play On';
}
}
// Stop autoplay
function stopAutoplay() {
if (autoplayInterval) {
clearInterval(autoplayInterval);
autoplayInterval = null;
}
autoplayBtn.classList.remove('active');
playIcon.style.display = 'block';
pauseIcon.style.display = 'none';
autoplayText.textContent = 'Auto-play Off';
}
// Toggle autoplay
function toggleAutoplay() {
isAutoplay = !isAutoplay;
if (isAutoplay) {
startAutoplay();
} else {
stopAutoplay();
}
}
// Event listeners
prevBtn.addEventListener('click', prevSlide);
nextBtn.addEventListener('click', nextSlide);
autoplayBtn.addEventListener('click', toggleAutoplay);
// Dot navigation
dots.forEach((dot, index) => {
dot.addEventListener('click', () => {
goToSlide(index);
});
});
// Keyboard navigation
document.addEventListener('keydown', (e) => {
if (slider.matches(':hover') || document.activeElement.closest('.testimonial-slider')) {
switch (e.key) {
case 'ArrowLeft':
prevSlide();
break;
case 'ArrowRight':
nextSlide();
break;
case ' ':
e.preventDefault();
toggleAutoplay();
break;
}
}
});
// Touch/swipe support for mobile
let touchStartX = 0;
let touchEndX = 0;
let touchStartY = 0;
let touchEndY = 0;
slider.addEventListener('touchstart', (e) => {
touchStartX = e.changedTouches[0].screenX;
touchStartY = e.changedTouches[0].screenY;
});
slider.addEventListener('touchend', (e) => {
touchEndX = e.changedTouches[0].screenX;
touchEndY = e.changedTouches[0].screenY;
handleSwipe();
});
function handleSwipe() {
const swipeThreshold = 50;
const diffX = touchStartX - touchEndX;
const diffY = Math.abs(touchStartY - touchEndY);
// Only handle horizontal swipes (ignore vertical scrolling)
if (Math.abs(diffX) > swipeThreshold && diffY < 100) {
if (diffX > 0) {
// Swipe left - next slide
nextSlide();
} else {
// Swipe right - previous slide
prevSlide();
}
}
}
// Pause autoplay on hover
slider.addEventListener('mouseenter', () => {
if (isAutoplay && autoplayInterval) {
clearInterval(autoplayInterval);
}
});
slider.addEventListener('mouseleave', () => {
if (isAutoplay) {
startAutoplay();
}
});
// Pause autoplay when tab is not visible
document.addEventListener('visibilitychange', () => {
if (document.hidden) {
if (autoplayInterval) {
clearInterval(autoplayInterval);
}
} else if (isAutoplay) {
startAutoplay();
}
});
// Animate statistics on scroll
function animateStats() {
const stats = document.querySelectorAll('.stat-number');
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const target = entry.target;
const finalValue = target.textContent;
// Extract number from text
const match = finalValue.match(/([0-9.]+)/);
if (match) {
const number = parseFloat(match[1]);
const suffix = finalValue.replace(match[0], '');
animateNumber(target, 0, number, suffix, 2000);
observer.unobserve(target);
}
}
});
});
stats.forEach(stat => observer.observe(stat));
}
function animateNumber(element, start, end, suffix, duration) {
const startTime = performance.now();
function update(currentTime) {
const elapsed = currentTime - startTime;
const progress = Math.min(elapsed / duration, 1);
// Easing function
const easeOut = 1 - Math.pow(1 - progress, 3);
const current = start + (end - start) * easeOut;
// Format number based on original format
let displayValue;
if (end % 1 === 0) {
displayValue = Math.floor(current);
} else {
displayValue = current.toFixed(1);
}
element.textContent = displayValue + suffix;
if (progress < 1) {
requestAnimationFrame(update);
}
}
requestAnimationFrame(update);
}
// Initialize everything
initSlider();
animateStats();
// Add focus management for accessibility
slider.addEventListener('focusin', () => {
if (isAutoplay && autoplayInterval) {
clearInterval(autoplayInterval);
}
});
slider.addEventListener('focusout', (e) => {
// Only restart autoplay if focus is completely leaving the slider
setTimeout(() => {
if (!slider.contains(document.activeElement) && isAutoplay) {
startAutoplay();
}
}, 100);
});
});