SolutionsCase StudiesAI ToolsResourcesAboutContact
Get Your Free AI Automation Audit Book a Free 30-Minute Strategy Call
Playground~/frontend Open editor

~/css/testimonials

7 CSS Testimonials & Reviews

6 Pure CSS1 with JSPublished 2026-10-05Free · no sign-up

Seven ways to show what customers say: a classic quote card, a grid of short star-rated reviews, a swipeable slider, one large featured quote, an average rating with a breakdown, a review styled like a social post and a slowly scrolling ribbon of short quotes.

01. Classic Quote Card

TestimonialCard

A testimonial card built from a figure with a blockquote and a figcaption naming the person, which is the semantic pattern for a quote with attribution. The large quotation mark is decoration drawn with a pseudo-element, and the initials avatar needs no photo.

View code
<figure class="tm1"><blockquote><p>We moved our whole catalogue in a weekend, and support answered every question within the hour.</p></blockquote><figcaption><span class="av" aria-hidden="true">MO</span><span><b>Mira Okafor</b><small>Owner, Kiln &amp; Co</small></span></figcaption></figure>
.tm1 { position: relative; width: 300px; max-width: 100%; box-sizing: border-box; margin: 0; padding: 28px 22px 20px; border: 1px solid #e4e7ec; border-radius: 18px; background: #fff; font-family: Inter, system-ui, sans-serif; color: #101828; }
.tm1::before { content: "\201C"; position: absolute; top: -8px; left: 18px; color: #7f56d9; font: 800 64px Georgia, serif; line-height: 1; }
.tm1 blockquote { margin: 0; }
.tm1 p { margin: 0; font-size: 16px; line-height: 1.55; }
.tm1 figcaption { display: flex; align-items: center; gap: 10px; margin-top: 16px; }
.tm1 .av { display: grid; place-items: center; width: 40px; height: 40px; border-radius: 50%; background: #f4ebff; color: #53389e; font-weight: 800; font-size: 14px; }
.tm1 figcaption > span:last-child { display: grid; }
.tm1 small { color: #475467; font-size: 13px; }

02. Review Grid with Star Ratings

TestimonialGrid

Three short reviews in a responsive grid. The stars are a decorative row of characters hidden from screen readers, with the rating given as text such as Rated 5 out of 5, so the score is not lost for people who cannot see the stars.

View code
<div class="tm2"><figure><p class="st"><span aria-hidden="true">★★★★★</span><span class="sr">Rated 5 out of 5</span></p><blockquote>Arrived in two days and fits perfectly.</blockquote><figcaption>Jonas, Leipzig</figcaption></figure><figure><p class="st"><span aria-hidden="true">★★★★☆</span><span class="sr">Rated 4 out of 5</span></p><blockquote>Lovely colour. The strap could be longer.</blockquote><figcaption>Priya, Leeds</figcaption></figure><figure><p class="st"><span aria-hidden="true">★★★★★</span><span class="sr">Rated 5 out of 5</span></p><blockquote>Third one I have bought. Still going strong.</blockquote><figcaption>Tomás, Porto</figcaption></figure></div>
.tm2 { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 12px; width: 520px; max-width: 100%; box-sizing: border-box; font-family: Inter, system-ui, sans-serif; }
.tm2 figure { margin: 0; padding: 14px; border: 1px solid #e4e7ec; border-radius: 14px; background: #fff; }
.tm2 .st { margin: 0 0 6px; color: #b54708; letter-spacing: 2px; }
.tm2 .sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
.tm2 blockquote { margin: 0; color: #101828; font-size: 14px; line-height: 1.5; }
.tm2 figcaption { margin-top: 8px; color: #475467; font-size: 13px; font-weight: 600; }

03. Scroll-Snap Testimonial Slider

TestimonialCarousel

Testimonials in a horizontal scroll container with scroll-snap, so it can be swiped on touch screens and scrolled with a trackpad. Previous and next buttons scroll by one card with scrollBy, and the region is labelled so screen reader users know what it holds.

View code
<section class="tm3" aria-label="Customer stories"><div class="track" tabindex="0"><figure><blockquote>Setup took ten minutes. I expected a day.</blockquote><figcaption>Lena · Studio Nord</figcaption></figure><figure><blockquote>Our checkout finally feels fast on phones.</blockquote><figcaption>Arjun · Brew Lab</figcaption></figure><figure><blockquote>The team answered on a Sunday. Unheard of.</blockquote><figcaption>Sofia · Linea Home</figcaption></figure></div><div class="nav"><button type="button" aria-label="Previous story">&larr;</button><button type="button" aria-label="Next story">&rarr;</button></div></section>
.tm3 { width: 300px; max-width: 100%; font-family: Inter, system-ui, sans-serif; }
.tm3 .track { display: flex; gap: 12px; overflow-x: auto; scroll-snap-type: x mandatory; scrollbar-width: none; border-radius: 16px; }
.tm3 .track::-webkit-scrollbar { display: none; }
.tm3 figure { flex: 0 0 100%; box-sizing: border-box; margin: 0; padding: 22px; border-radius: 16px; background: #161d31; border: 1px solid #28324f; scroll-snap-align: start; }
.tm3 blockquote { margin: 0; color: #eef2ff; font-size: 17px; line-height: 1.5; }
.tm3 figcaption { margin-top: 12px; color: #9aa6c7; font-size: 13px; }
.tm3 .nav { display: flex; justify-content: flex-end; gap: 8px; margin-top: 10px; }
.tm3 button { width: 40px; height: 40px; border: 1px solid #36406a; border-radius: 50%; background: #121828; color: #e0e7ff; font-size: 18px; cursor: pointer; }
.tm3 button:focus-visible, .tm3 .track:focus-visible { outline: 2px solid #818cf8; outline-offset: 2px; }
var t = document.querySelector('.tm3 .track'), bs = document.querySelectorAll('.tm3 button');
bs[0].onclick = function () { t.scrollBy({ left: -t.clientWidth, behavior: 'smooth' }); };
bs[1].onclick = function () { t.scrollBy({ left: t.clientWidth, behavior: 'smooth' }); };

05. Rating Summary with Breakdown

ReviewsData

An average score with bars for each star level, the block that usually sits above a list of reviews. Each bar is a meter element with a text label, so the numbers are available to assistive technology, and the bar colour comes from a CSS accent.

View code
<section class="tm5" aria-labelledby="tm5h"><h3 id="tm5h">Customer reviews</h3><p class="avg"><b>4.6</b> out of 5 <span>· 312 reviews</span></p><ul><li><span>5 star</span><meter min="0" max="100" value="72">72%</meter><span>72%</span></li><li><span>4 star</span><meter min="0" max="100" value="18">18%</meter><span>18%</span></li><li><span>3 star</span><meter min="0" max="100" value="6">6%</meter><span>6%</span></li><li><span>2 star</span><meter min="0" max="100" value="2">2%</meter><span>2%</span></li><li><span>1 star</span><meter min="0" max="100" value="2">2%</meter><span>2%</span></li></ul></section>
.tm5 { width: 300px; max-width: 100%; box-sizing: border-box; font-family: Inter, system-ui, sans-serif; color: #101828; }
.tm5 h3 { margin: 0 0 4px; font-size: 17px; }
.tm5 .avg { margin: 0 0 12px; color: #344054; } .tm5 .avg b { font-size: 28px; color: #101828; } .tm5 .avg span { color: #475467; }
.tm5 ul { margin: 0; padding: 0; list-style: none; display: grid; gap: 6px; }
.tm5 li { display: grid; grid-template-columns: 48px 1fr 36px; align-items: center; gap: 8px; font-size: 13px; color: #344054; }
.tm5 meter { width: 100%; height: 10px; }
.tm5 meter::-webkit-meter-bar { background: #eaecf0; border: 0; border-radius: 5px; height: 10px; }
.tm5 meter::-webkit-meter-optimum-value { background: #f79009; border-radius: 5px; }
.tm5 meter::-moz-meter-bar { background: #f79009; border-radius: 5px; }
.tm5 li span:last-child { text-align: right; }

06. Social Post Style Review

TestimonialSocial

A review laid out like a social media post, with a handle, a date in a time element and the post text. It is a styled figure, not an embed, so it loads instantly and sends nothing to a third party. Link the date to the original post if you have permission to quote it.

View code
<figure class="tm6"><figcaption><span class="av" aria-hidden="true">RK</span><span class="who"><b>Rafa K.</b><span>@rafabuilds</span></span><time datetime="2026-09-14">14 Sep</time></figcaption><blockquote>Rebuilt our pricing page with these components over lunch. Conversion is up and the page weighs less than the old hero image.</blockquote></figure>
.tm6 { width: 320px; max-width: 100%; box-sizing: border-box; margin: 0; padding: 16px; border: 1px solid #e4e7ec; border-radius: 16px; background: #fff; font-family: Inter, system-ui, sans-serif; color: #101828; }
.tm6 figcaption { display: flex; align-items: center; gap: 10px; }
.tm6 .av { display: grid; place-items: center; width: 40px; height: 40px; border-radius: 50%; background: #101828; color: #fff; font-weight: 800; font-size: 13px; }
.tm6 .who { display: grid; flex: 1; min-width: 0; } .tm6 .who span { color: #475467; font-size: 13px; }
.tm6 time { color: #475467; font-size: 13px; }
.tm6 blockquote { margin: 12px 0 0; font-size: 15px; line-height: 1.5; }

07. Scrolling Review Ribbon

TestimonialMarquee

Short review snippets drift sideways in a continuous ribbon. The list is duplicated once, the duplicate is aria-hidden so nothing is read twice, and the motion pauses on hover and stops entirely when reduced motion is requested, at which point the ribbon can be scrolled by hand.

View code
<div class="tm7"><ul class="row"><li>“Fast checkout.” <b>Ines</b></li><li>“Lovely packaging.” <b>Marc</b></li><li>“Exactly as pictured.” <b>Yuki</b></li><li>“Will order again.” <b>Ola</b></li></ul><ul class="row" aria-hidden="true"><li>“Fast checkout.” <b>Ines</b></li><li>“Lovely packaging.” <b>Marc</b></li><li>“Exactly as pictured.” <b>Yuki</b></li><li>“Will order again.” <b>Ola</b></li></ul></div>
.tm7 { display: flex; width: 340px; max-width: 100%; overflow: hidden; font-family: Inter, system-ui, sans-serif; -webkit-mask: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent); mask: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent); }
.tm7 .row { display: flex; gap: 10px; flex: none; margin: 0; padding: 0 10px 0 0; list-style: none; animation: tm7 18s linear infinite; }
.tm7:hover .row { animation-play-state: paused; }
.tm7 li { flex: none; padding: 10px 14px; border: 1px solid #2b3452; border-radius: 999px; background: #151b2e; color: #dbe3ff; font-size: 14px; white-space: nowrap; }
.tm7 b { color: #a5b4fc; font-weight: 600; }
@keyframes tm7 { to { transform: translateX(-100%); } }
@media (prefers-reduced-motion: reduce) { .tm7 { overflow-x: auto; } .tm7 .row { animation: none; } .tm7 .row[aria-hidden] { display: none; } }

About these CSS Testimonials & Reviews

Use figure, blockquote and figcaption

A testimonial is a quotation with an attribution. Wrapping it in <figure> with the words in <blockquote> and the name in <figcaption> keeps the person and the quote together for assistive technology.

Stars need words

A row of star characters means nothing to a screen reader, or is read as five separate stars. Hide the stars with aria-hidden and add a text rating such as Rated 4 out of 5.

Real quotes only

Use quotes you have permission to publish, from real customers, with their real name or initials. Invented reviews mislead buyers and break consumer law in many countries; the names in these demos are placeholders to replace.

Moving testimonials

Auto-scrolling reviews should pause on hover and stop under prefers-reduced-motion. Duplicate content used to make a loop seamless must be aria-hidden so it is not read twice.

Frequently asked questions

Should I add review schema markup?

Only for reviews of your products collected on your site, and only when they are visible on the page. Search engines ignore self-serving reviews of your own business.

Can the slider work without JavaScript?

Yes. Scroll-snap makes it swipeable on its own; the script only powers the arrow buttons.

Where do the avatars come from?

They are initials in a circle, which needs no photo and works at any size.