Testimonial Cards with Photos
Three bordered testimonial cards with photo, purchase detail, star rating and quote, plus an accent circle. React and Tailwind CSS.
TestimonialCardsWithPhotos.tsx
// Client stories: centred heading, three bordered cards with photo, name,
// purchase detail, star rating and quote, plus a soft accent circle in the corner.
// Pure Tailwind, no dependencies. Works with Tailwind v3 and v4.
type Testimonial = { name: string; detail: string; photo: string; rating: number; quote: string };
type Props = {
eyebrow?: string;
heading?: string;
intro?: string;
testimonials?: Testimonial[];
};
const photo = (id: string) => `https://images.unsplash.com/photo-${id}?w=160&h=160&q=80&auto=format&fit=crop&crop=faces`;
const DEFAULT_TESTIMONIALS: Testimonial[] = [
{ name: "Robert & Claire Ashford", detail: "Purchased: Casa Serena Villa", photo: photo("1499952127939-9bbf5af6c51c"), rating: 5, quote: "Exceptional from beginning to end. They understood exactly what we were looking for and found a home that exceeded every expectation." },
{ name: "Daniel Mercer", detail: "Purchased: The Meridian Penthouse", photo: photo("1507003211169-0a1dd7228f2d"), rating: 5, quote: "The professionalism and market knowledge throughout our purchase was unmatched. A truly white-glove experience." },
{ name: "Isabelle Torres", detail: "Rented in Chicago", photo: photo("1534528741775-53994a69daeb"), rating: 5, quote: "Responsive, honest and genuinely invested in finding the right fit rather than just closing a deal." },
];
const Star = () => (
<svg viewBox="0 0 24 24" aria-hidden className="h-[18px] w-[18px] fill-[#F66F00]">
<path d="m12 2 3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01z" />
</svg>
);
export default function TestimonialsCircle({
eyebrow = "Client stories",
heading = "What our clients say",
intro = "Don't just take our word for it. Hear from the families and investors who trusted us with their most important decisions.",
testimonials = DEFAULT_TESTIMONIALS,
}: Props) {
return (
<section className="relative overflow-hidden bg-white px-5 py-20 font-['Manrope',ui-sans-serif,system-ui,sans-serif] antialiased md:px-10 md:py-28">
{/* Decorative; hidden on phones where it would sit behind the heading */}
<div aria-hidden className="pointer-events-none absolute -right-24 -top-24 hidden h-96 w-96 rounded-full bg-[#F66F00]/90 md:block" />
<div className="relative z-10 mx-auto max-w-7xl">
<div className="mb-16 text-center">
<span className="mb-3 block text-xs font-bold uppercase tracking-[0.2em] text-[#F66F00]">{eyebrow}</span>
<h2 className="mb-4 font-['Bricolage_Grotesque',ui-sans-serif,system-ui,sans-serif] text-[clamp(36px,5vw,64px)] font-semibold leading-[1.1] text-neutral-900">{heading}</h2>
<p className="mx-auto max-w-lg font-semibold leading-relaxed text-neutral-700">{intro}</p>
</div>
<div className="grid grid-cols-1 gap-6 md:grid-cols-3 lg:gap-10">
{testimonials.map((t) => (
<figure key={t.name} className="rounded-2xl border border-neutral-200 bg-white/80 p-8 backdrop-blur-sm">
<figcaption className="mb-12 flex items-center gap-4 border-b border-neutral-200 pb-8">
<img src={t.photo} alt={t.name} className="h-[72px] w-[72px] rounded-full object-cover" />
<div>
<div className="text-xl font-semibold text-neutral-900">{t.name}</div>
<div className="mt-0.5 font-medium text-neutral-700">{t.detail}</div>
</div>
</figcaption>
<div className="mb-4 flex gap-2" aria-label={`${t.rating} out of 5 stars`}>
{Array.from({ length: t.rating }).map((_, i) => (
<Star key={i} />
))}
</div>
<blockquote className="text-xl font-semibold leading-relaxed text-neutral-900">“{t.quote}”</blockquote>
</figure>
))}
</div>
</div>
</section>
);
}
How to use it
- Make sure your Next.js or React project has Tailwind CSS set up.
- Create
components/TestimonialCardsWithPhotos.tsxand paste the code. - Import it into a page and replace the placeholder text and images with your own.
More free components
All testimonials →
Ready for a faster site that's easier to edit?
Book a free 30-minute call. We'll review your current site and send a fixed-price plan. No pressure, no pitch.
Book Free Call No commitment required


