Rotating display of testimonials.
“Cut our reporting time in half.”— Priya, Northwind
“Support that actually responds fast.”— Omar, Cobalt
“Rolled out to 40 people in a day.”— Lena, Fenwick
<div class="carousel" data-active="1" style="--accent:#241430;">
<button type="button" class="carousel__arrow carousel__arrow--prev" aria-label="Previous testimonial">‹</button>
<div class="carousel__track">
<blockquote class="carousel__slide" data-slide="1">“Cut our reporting time in half.”<cite>— Priya, Northwind</cite></blockquote>
<blockquote class="carousel__slide" data-slide="2">“Support that actually responds fast.”<cite>— Omar, Cobalt</cite></blockquote>
<blockquote class="carousel__slide" data-slide="3">“Rolled out to 40 people in a day.”<cite>— Lena, Fenwick</cite></blockquote>
</div>
<button type="button" class="carousel__arrow carousel__arrow--next" aria-label="Next testimonial">›</button>
<div class="carousel__dots" role="tablist" aria-label="Testimonials">
<span class="carousel__dot" data-dot="1"></span>
<span class="carousel__dot" data-dot="2"></span>
<span class="carousel__dot" data-dot="3"></span>
</div>
</div>
<style>
.carousel { font: 16px/1.5 system-ui, sans-serif; color: #241430; max-width: 360px; text-align: center; padding: 24px; position: relative; }
.carousel__slide { display: none; margin: 0 0 16px; font-size: 17px; font-weight: 500; }
.carousel__slide cite { display: block; margin-top: 10px; font-size: 13px; font-style: normal; color: #241430aa; }
.carousel[data-active="1"] .carousel__slide[data-slide="1"],
.carousel[data-active="2"] .carousel__slide[data-slide="2"],
.carousel[data-active="3"] .carousel__slide[data-slide="3"] { display: block; }
.carousel__arrow { position: absolute; top: 50%; transform: translateY(-50%); background: none; border: none; font-size: 26px; color: var(--accent); cursor: pointer; padding: 4px 8px; }
.carousel__arrow--prev { left: 0; }
.carousel__arrow--next { right: 0; }
.carousel__arrow:hover, .carousel__arrow:focus-visible { opacity: .7; }
.carousel__dots { display: flex; gap: 8px; justify-content: center; }
.carousel__dot { width: 8px; height: 8px; border-radius: 50%; background: #24143025; }
.carousel[data-active="1"] .carousel__dot[data-dot="1"],
.carousel[data-active="2"] .carousel__dot[data-dot="2"],
.carousel[data-active="3"] .carousel__dot[data-dot="3"] { background: var(--accent); }
</style><div class="carousel-tw carousel-tw--1 relative font-sans text-[#241430] max-w-[360px] text-center p-6" style="--accent:#241430;">
<button type="button" class="absolute top-1/2 left-0 -translate-y-1/2 bg-transparent border-0 text-2xl cursor-pointer px-2 hover:opacity-70" style="color:#241430;" aria-label="Previous testimonial">‹</button>
<div>
<blockquote class="carousel-tw__slide hidden m-0 mb-4 text-[17px] font-medium" data-slide="1">“Cut our reporting time in half.”<cite class="block mt-2.5 text-[13px] not-italic text-[#241430]/65">— Priya, Northwind</cite></blockquote>
<blockquote class="carousel-tw__slide hidden m-0 mb-4 text-[17px] font-medium" data-slide="2">“Support that actually responds fast.”<cite class="block mt-2.5 text-[13px] not-italic text-[#241430]/65">— Omar, Cobalt</cite></blockquote>
<blockquote class="carousel-tw__slide hidden m-0 mb-4 text-[17px] font-medium" data-slide="3">“Rolled out to 40 people in a day.”<cite class="block mt-2.5 text-[13px] not-italic text-[#241430]/65">— Lena, Fenwick</cite></blockquote>
</div>
<button type="button" class="absolute top-1/2 right-0 -translate-y-1/2 bg-transparent border-0 text-2xl cursor-pointer px-2 hover:opacity-70" style="color:#241430;" aria-label="Next testimonial">›</button>
<div class="flex gap-2 justify-center" role="tablist" aria-label="Testimonials">
<span class="carousel-tw__dot w-2 h-2 rounded-full bg-[#24143025]" data-dot="1"></span>
<span class="carousel-tw__dot w-2 h-2 rounded-full bg-[#24143025]" data-dot="2"></span>
<span class="carousel-tw__dot w-2 h-2 rounded-full bg-[#24143025]" data-dot="3"></span>
</div>
</div>
<style>
.carousel-tw--1 .carousel-tw__slide[data-slide="1"], .carousel-tw--2 .carousel-tw__slide[data-slide="2"], .carousel-tw--3 .carousel-tw__slide[data-slide="3"] { display: block; }
.carousel-tw--1 .carousel-tw__dot[data-dot="1"], .carousel-tw--2 .carousel-tw__dot[data-dot="2"], .carousel-tw--3 .carousel-tw__dot[data-dot="3"] { background: var(--accent); }
</style>import { useState } from "react";
export function TestimonialCarousel({
activeSlide = "1",
accent = "#241430",
showArrows = true,
}) {
const slides = [
{ quote: "Cut our reporting time in half.", cite: "Priya, Northwind" },
{ quote: "Support that actually responds fast.", cite: "Omar, Cobalt" },
{ quote: "Rolled out to 40 people in a day.", cite: "Lena, Fenwick" },
];
const [index, setIndex] = useState(Number(activeSlide) - 1);
const move = (delta) => setIndex((i) => (i + delta + slides.length) % slides.length);
return (
<div style={{ font: "16px/1.5 system-ui, sans-serif", color: "#241430", maxWidth: 360, textAlign: "center",
padding: 24, position: "relative" }}>
{showArrows && (
<button type="button" onClick={() => move(-1)} aria-label="Previous testimonial" style={{ position: "absolute",
top: "50%", left: 0, transform: "translateY(-50%)", background: "none", border: "none", fontSize: 26,
color: accent, cursor: "pointer", padding: "4px 8px" }}>‹</button>
)}
<blockquote style={{ margin: "0 0 16px", fontSize: 17, fontWeight: 500 }}>
“{slides[index].quote}”
<cite style={{ display: "block", marginTop: 10, fontSize: 13, fontStyle: "normal", color: "#241430aa" }}>— {slides[index].cite}</cite>
</blockquote>
{showArrows && (
<button type="button" onClick={() => move(1)} aria-label="Next testimonial" style={{ position: "absolute",
top: "50%", right: 0, transform: "translateY(-50%)", background: "none", border: "none", fontSize: 26,
color: accent, cursor: "pointer", padding: "4px 8px" }}>›</button>
)}
<div role="tablist" aria-label="Testimonials" style={{ display: "flex", gap: 8, justifyContent: "center" }}>
{slides.map((_, i) => (
<span key={i} style={{ width: 8, height: 8, borderRadius: "50%", background: i === index ? accent : "#24143025" }} />
))}
</div>
</div>
);
}