Vet — Happy Clients
A warm veterinary testimonials carousel with prev and next controls, dot navigation and auto-advance. Each slide shows the owner name, pet name with a species emoji, a star rating and a quote, sitting above a trust band counting pets cared for, years serving and satisfaction rate.
MCP
Code
:root {
--teal: #179c8e;
--teal-d: #0f7f73;
--teal-50: #e6f5f2;
--coral: #ff8a5c;
--ink: #173a36;
--muted: #6b827e;
--bg: #f2f8f6;
--white: #ffffff;
--star: #ffb84d;
--radius: 24px;
--shadow: 0 18px 40px -22px rgba(15, 127, 115, 0.45);
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: 'Inter', system-ui, -apple-system, sans-serif;
background: var(--bg);
color: var(--ink);
-webkit-font-smoothing: antialiased;
line-height: 1.55;
padding: 48px 20px;
display: flex;
justify-content: center;
}
.testimonials {
width: 100%;
max-width: 680px;
}
.testimonials__head {
text-align: center;
margin-bottom: 28px;
}
.eyebrow {
display: inline-block;
font-size: 0.8rem;
font-weight: 600;
letter-spacing: 0.02em;
color: var(--teal-d);
background: var(--teal-50);
padding: 6px 14px;
border-radius: 999px;
margin-bottom: 14px;
}
.testimonials__head h2 {
font-size: 1.8rem;
font-weight: 800;
letter-spacing: -0.02em;
}
.lede {
color: var(--muted);
font-size: 0.98rem;
margin-top: 8px;
}
/* Carousel */
.carousel {
position: relative;
display: flex;
align-items: center;
gap: 10px;
}
.carousel__viewport {
overflow: hidden;
border-radius: var(--radius);
flex: 1;
}
.track {
display: flex;
list-style: none;
transition: transform 0.55s cubic-bezier(0.22, 0.61, 0.36, 1);
}
.slide {
flex: 0 0 100%;
min-width: 0;
padding: 4px;
}
.card {
background: var(--white);
border: 1px solid var(--teal-50);
border-radius: var(--radius);
padding: 32px 30px;
box-shadow: var(--shadow);
min-height: 252px;
display: flex;
flex-direction: column;
}
.stars {
color: var(--star);
font-size: 1.15rem;
letter-spacing: 2px;
margin-bottom: 16px;
}
.star--off {
color: #e3e9e7;
}
.quote {
font-size: 1.12rem;
font-weight: 500;
color: var(--ink);
line-height: 1.5;
flex: 1;
}
.client {
display: flex;
align-items: center;
gap: 14px;
margin-top: 24px;
padding-top: 20px;
border-top: 1px dashed #d7e7e3;
}
.avatar {
width: 48px;
height: 48px;
flex: 0 0 48px;
display: grid;
place-items: center;
font-size: 1.5rem;
background: var(--teal-50);
border-radius: 50%;
}
.client__name {
font-weight: 700;
font-size: 0.98rem;
}
.client__pet {
color: var(--muted);
font-size: 0.86rem;
}
/* Nav buttons */
.nav {
flex: 0 0 44px;
width: 44px;
height: 44px;
border-radius: 50%;
border: 1px solid var(--teal-50);
background: var(--white);
color: var(--teal-d);
font-size: 1.6rem;
line-height: 1;
cursor: pointer;
display: grid;
place-items: center;
box-shadow: 0 8px 18px -12px rgba(15, 127, 115, 0.5);
transition: transform 0.18s ease, background 0.18s ease, color 0.18s ease;
}
.nav:hover {
background: var(--teal);
color: var(--white);
transform: scale(1.07);
}
.nav:active {
transform: scale(0.96);
}
.nav:focus-visible {
outline: 3px solid var(--coral);
outline-offset: 2px;
}
/* Dots */
.dots {
display: flex;
justify-content: center;
gap: 10px;
margin: 22px 0 30px;
}
.dot {
width: 10px;
height: 10px;
border-radius: 50%;
border: none;
background: #c6ded8;
cursor: pointer;
padding: 0;
transition: background 0.2s ease, transform 0.2s ease, width 0.25s ease;
}
.dot:hover {
background: var(--teal);
}
.dot[aria-selected='true'] {
background: var(--teal);
width: 26px;
border-radius: 999px;
}
.dot:focus-visible {
outline: 3px solid var(--coral);
outline-offset: 3px;
}
/* Trust band */
.trust {
display: flex;
align-items: center;
justify-content: space-around;
gap: 12px;
background: linear-gradient(135deg, var(--teal) 0%, var(--teal-d) 100%);
color: var(--white);
border-radius: var(--radius);
padding: 26px 22px;
box-shadow: var(--shadow);
}
.trust__num {
font-size: 1.7rem;
font-weight: 800;
letter-spacing: -0.01em;
}
.trust__label {
font-size: 0.82rem;
opacity: 0.9;
margin-top: 2px;
}
.trust__sep {
width: 1px;
align-self: stretch;
background: rgba(255, 255, 255, 0.25);
}
@media (prefers-reduced-motion: reduce) {
.track {
transition: none;
}
}
@media (max-width: 520px) {
body {
padding: 28px 14px;
}
.testimonials__head h2 {
font-size: 1.45rem;
}
.card {
padding: 26px 22px;
min-height: 0;
}
.quote {
font-size: 1.02rem;
}
.nav {
flex-basis: 38px;
width: 38px;
height: 38px;
font-size: 1.4rem;
}
.trust {
flex-direction: column;
gap: 16px;
}
.trust__sep {
width: 60%;
height: 1px;
align-self: center;
}
}(function () {
'use strict';
var carousel = document.getElementById('carousel');
var track = document.getElementById('track');
var slides = track ? Array.prototype.slice.call(track.children) : [];
var prevBtn = document.getElementById('prev');
var nextBtn = document.getElementById('next');
var dotsWrap = document.getElementById('dots');
if (!track || slides.length === 0) return;
var index = 0;
var count = slides.length;
var reduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
var AUTO_MS = 5500;
var timer = null;
// Build dots
var dots = [];
slides.forEach(function (_, i) {
var b = document.createElement('button');
b.className = 'dot';
b.type = 'button';
b.setAttribute('role', 'tab');
b.setAttribute('aria-label', 'Go to testimonial ' + (i + 1));
b.addEventListener('click', function () {
goTo(i);
restart();
});
dotsWrap.appendChild(b);
dots.push(b);
});
function render() {
track.style.transform = 'translateX(' + -index * 100 + '%)';
dots.forEach(function (d, i) {
d.setAttribute('aria-selected', i === index ? 'true' : 'false');
});
slides.forEach(function (s, i) {
s.setAttribute('aria-hidden', i === index ? 'false' : 'true');
});
}
function goTo(i) {
index = (i + count) % count;
render();
}
function next() { goTo(index + 1); }
function prev() { goTo(index - 1); }
function start() {
if (reduceMotion || timer) return;
timer = window.setInterval(next, AUTO_MS);
}
function stop() {
if (timer) {
window.clearInterval(timer);
timer = null;
}
}
function restart() {
stop();
start();
}
nextBtn.addEventListener('click', function () { next(); restart(); });
prevBtn.addEventListener('click', function () { prev(); restart(); });
// Keyboard arrows when carousel has focus
carousel.addEventListener('keydown', function (e) {
if (e.key === 'ArrowRight') { e.preventDefault(); next(); restart(); }
else if (e.key === 'ArrowLeft') { e.preventDefault(); prev(); restart(); }
});
// Pause on hover / focus
carousel.addEventListener('mouseenter', stop);
carousel.addEventListener('mouseleave', start);
carousel.addEventListener('focusin', stop);
carousel.addEventListener('focusout', start);
document.addEventListener('visibilitychange', function () {
if (document.hidden) stop(); else start();
});
// Animate trust counters once when scrolled into view
var nums = Array.prototype.slice.call(document.querySelectorAll('.trust__num'));
function animateCount(el) {
var target = parseInt(el.getAttribute('data-count'), 10) || 0;
var suffix = el.getAttribute('data-suffix') || '';
if (reduceMotion) {
el.textContent = target.toLocaleString() + suffix;
return;
}
var startTime = null;
var dur = 1400;
function step(ts) {
if (startTime === null) startTime = ts;
var p = Math.min((ts - startTime) / dur, 1);
var eased = 1 - Math.pow(1 - p, 3);
el.textContent = Math.round(target * eased).toLocaleString() + suffix;
if (p < 1) requestAnimationFrame(step);
}
requestAnimationFrame(step);
}
if ('IntersectionObserver' in window && nums.length) {
var io = new IntersectionObserver(function (entries) {
entries.forEach(function (entry) {
if (entry.isIntersecting) {
animateCount(entry.target);
io.unobserve(entry.target);
}
});
}, { threshold: 0.4 });
nums.forEach(function (n) { io.observe(n); });
} else {
nums.forEach(animateCount);
}
render();
start();
})();<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vet — Happy Clients</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="style.css" />
</head>
<body>
<section class="testimonials" aria-labelledby="t-heading">
<header class="testimonials__head">
<span class="eyebrow">🐾 From our families</span>
<h2 id="t-heading">Happy clients, healthier pets</h2>
<p class="lede">Real words from the people who trust Brightpaw Veterinary with their best friends.</p>
</header>
<div class="carousel" id="carousel" aria-roledescription="carousel" aria-label="Client testimonials">
<button class="nav nav--prev" type="button" id="prev" aria-label="Previous testimonial">
<span aria-hidden="true">‹</span>
</button>
<div class="carousel__viewport">
<ul class="track" id="track">
<li class="slide" role="group" aria-roledescription="slide" aria-label="1 of 5">
<article class="card">
<div class="stars" role="img" aria-label="Rated 5 out of 5 stars">★★★★★</div>
<blockquote class="quote">“Dr. Okafor caught Mochi's heart murmur early and walked us through every option without ever rushing us. We left calm and confident.”</blockquote>
<div class="client">
<span class="avatar" aria-hidden="true">🐱</span>
<div class="client__meta">
<p class="client__name">Priya Raman</p>
<p class="client__pet">Mochi the cat 🐱</p>
</div>
</div>
</article>
</li>
<li class="slide" role="group" aria-roledescription="slide" aria-label="2 of 5">
<article class="card">
<div class="stars" role="img" aria-label="Rated 5 out of 5 stars">★★★★★</div>
<blockquote class="quote">“Bailey hates the vet — except this one. The staff sat on the floor with him until he relaxed. Best dental cleaning we've ever had.”</blockquote>
<div class="client">
<span class="avatar" aria-hidden="true">🐶</span>
<div class="client__meta">
<p class="client__name">Marcus Delgado</p>
<p class="client__pet">Bailey the dog 🐶</p>
</div>
</div>
</article>
</li>
<li class="slide" role="group" aria-roledescription="slide" aria-label="3 of 5">
<article class="card">
<div class="stars" role="img" aria-label="Rated 4 out of 5 stars">★★★★<span class="star--off">★</span></div>
<blockquote class="quote">“They squeezed Pippin in the same morning he stopped eating. Turned out to be a tooth — fixed by lunch. The follow-up text the next day meant a lot.”</blockquote>
<div class="client">
<span class="avatar" aria-hidden="true">🐰</span>
<div class="client__meta">
<p class="client__name">Hannah Whitfield</p>
<p class="client__pet">Pippin the rabbit 🐰</p>
</div>
</div>
</article>
</li>
<li class="slide" role="group" aria-roledescription="slide" aria-label="4 of 5">
<article class="card">
<div class="stars" role="img" aria-label="Rated 5 out of 5 stars">★★★★★</div>
<blockquote class="quote">“Kiwi needed a wing splint and I was a wreck. The team explained the exotics plan in plain language and texted me photos of her recovery. Incredible care.”</blockquote>
<div class="client">
<span class="avatar" aria-hidden="true">🦜</span>
<div class="client__meta">
<p class="client__name">Theo Nakamura</p>
<p class="client__pet">Kiwi the parrot 🦜</p>
</div>
</div>
</article>
</li>
<li class="slide" role="group" aria-roledescription="slide" aria-label="5 of 5">
<article class="card">
<div class="stars" role="img" aria-label="Rated 5 out of 5 stars">★★★★★</div>
<blockquote class="quote">“Eleven years with Brightpaw and three rescue dogs later, I wouldn't trust anyone else. They remember every pet by name when we walk in.”</blockquote>
<div class="client">
<span class="avatar" aria-hidden="true">🐕</span>
<div class="client__meta">
<p class="client__name">Sofia Aranda</p>
<p class="client__pet">Rosie the dog 🐕</p>
</div>
</div>
</article>
</li>
</ul>
</div>
<button class="nav nav--next" type="button" id="next" aria-label="Next testimonial">
<span aria-hidden="true">›</span>
</button>
</div>
<div class="dots" id="dots" role="tablist" aria-label="Choose testimonial"></div>
<div class="trust" aria-label="Practice highlights">
<div class="trust__item">
<p class="trust__num" data-count="12480">0</p>
<p class="trust__label">Pets cared for</p>
</div>
<div class="trust__sep" aria-hidden="true"></div>
<div class="trust__item">
<p class="trust__num" data-count="18">0</p>
<p class="trust__label">Years serving</p>
</div>
<div class="trust__sep" aria-hidden="true"></div>
<div class="trust__item">
<p class="trust__num" data-count="98" data-suffix="%">0</p>
<p class="trust__label">Satisfaction</p>
</div>
</div>
</section>
<script src="script.js"></script>
</body>
</html>Happy Clients
A friendly veterinary testimonials section built for trust. Each card leads with a star rating and a heartfelt quote, then names the owner and their pet with a species emoji, so the praise feels personal. A carousel cycles through reviews with prev / next buttons and clickable dots, and it auto-advances every few seconds — pausing politely whenever the visitor hovers or focuses inside.
Below the cards a trust band reinforces the numbers that matter: pets cared for, years serving the
community and overall satisfaction. The whole thing is keyboard friendly, respects
prefers-reduced-motion, and collapses gracefully on small screens.
Everything runs on vanilla JS with no libraries, so it drops straight into any page.
Illustrative UI only — not for real veterinary use.