All Taste components
Testimonials
Testimonials — compact quote list
Eight one-line quotes with small avatars in a tidy two-column list, for lots of voices in little space.
8 short quotes · avatar + name + role · ruled rows · 2 columns, 1 when narrow
Short and sweet
In a sentence
“Setup took one coffee. I was taking bookings before lunch.”
Rosa Lindgren · Yoga teacher “The reminder texts alone halved our no-shows.”
Kofi Mensah · Barber “Clients reschedule themselves now. My phone is quiet.”
Alma Petrovic · Massage therapist “Three rooms, one calendar, zero double bookings.”
Ethan Cole · Manager, Fernhill Dental “I finally know which services actually fill my week.”
Nadia Haddad · Brow artist “Deposits at booking changed how Saturdays feel.”
Luca Bianchi · Tattoo studio owner “Parents book the next lesson before they leave the door.”
Grace Obi · Piano tutor “The intake form means I walk into every session prepared.”
Ola Nordin · Personal trainer
import { ArrowRight } from "lucide-react";
const quotes = [
{ quote: "Setup took one coffee. I was taking bookings before lunch.", name: "Rosa Lindgren", role: "Yoga teacher" },
{ quote: "The reminder texts alone halved our no-shows.", name: "Kofi Mensah", role: "Barber" },
{ quote: "Clients reschedule themselves now. My phone is quiet.", name: "Alma Petrovic", role: "Massage therapist" },
{ quote: "Three rooms, one calendar, zero double bookings.", name: "Ethan Cole", role: "Manager, Fernhill Dental" },
{ quote: "I finally know which services actually fill my week.", name: "Nadia Haddad", role: "Brow artist" },
{ quote: "Deposits at booking changed how Saturdays feel.", name: "Luca Bianchi", role: "Tattoo studio owner" },
{ quote: "Parents book the next lesson before they leave the door.", name: "Grace Obi", role: "Piano tutor" },
{ quote: "The intake form means I walk into every session prepared.", name: "Ola Nordin", role: "Personal trainer" },
];
const initials = (name: string) => name.split(" ").map((w) => w[0]).join("").slice(0, 2);
export function TestimonialsCompactList() {
return (
<section aria-labelledby="short-title" className="bg-bg px-5 py-12 font-sans sm:px-10 sm:py-20">
<div className="mx-auto max-w-6xl">
<div className="mb-10 flex flex-wrap items-end justify-between gap-x-8 gap-y-4">
<div className="grid gap-3">
<p className="text-[13px] font-medium text-primary">Short and sweet</p>
<h2 id="short-title" className="text-3xl font-semibold tracking-tight text-fg sm:text-4xl">In a sentence</h2>
</div>
<a href="/reviews" className="inline-flex items-center gap-1.5 text-sm font-medium text-primary hover:underline">
See all reviews <ArrowRight className="size-4" aria-hidden />
</a>
</div>
<ul className="grid gap-x-12 md:grid-cols-2">
{quotes.map((q) => (
<li key={q.name} className="border-t border-border">
<figure className="flex items-start gap-3.5 py-[18px]">
<span className="grid size-7 shrink-0 place-items-center rounded-full bg-primary-soft text-[11px] font-medium text-primary-soft-fg" aria-hidden>{initials(q.name)}</span>
<div className="grid min-w-0 gap-1">
<blockquote className="text-[15px] leading-normal text-fg"><p>“{q.quote}”</p></blockquote>
<figcaption className="text-[13px] text-fg-subtle"><span className="font-medium text-fg-muted">{q.name}</span> · {q.role}</figcaption>
</div>
</figure>
</li>
))}
</ul>
</div>
</section>
);
}
The code uses the Taste Tailwind preset. Make yours on the Taste page with Export my system.