Testimonials — Card Grid
Testimonial grid with avatar, name, role, and quote cards.
Testimonials cardavatar
Installation
npx shadcn@latest add @saastro/testimonials-01Preview
What people are saying
Hear from developers who use our blocks.
“These blocks saved me hours of work. The quality is outstanding and they integrate seamlessly with my Astro site.”
SC
Sarah Chen
Frontend Developer, Vercel
“Finally a block library that gets the developer experience right. Install, customize, ship.”
MR
Marco Rivera
CTO, StartupCo
“The attention to detail in these components is impressive. Responsive, accessible, and beautifully designed.”
EP
Emily Park
Designer, Studio
Source Code
import { Card, CardContent } from '@/components/ui/card';
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
import { cn } from '@/lib/utils';
type Testimonial = {
quote: string;
author: string;
role: string;
company?: string;
avatarUrl?: string;
};
type Testimonials01Props = {
title?: string;
description?: string;
testimonials: Testimonial[];
className?: string;
};
function getInitials(name: string): string {
return name
.split(' ')
.map((n) => n[0])
.join('')
.toUpperCase()
.slice(0, 2);
}
export function Testimonials01({
title,
description,
testimonials,
className,
}: Testimonials01Props) {
return (
<section className={cn('w-full px-6 py-24 md:py-32', className)}>
<div className="mx-auto max-w-6xl">
{(title || description) && (
<div className="mx-auto mb-16 max-w-2xl text-center">
{title && <h2 className="text-3xl font-bold tracking-tight sm:text-4xl">{title}</h2>}
{description && <p className="mt-4 text-lg text-muted-foreground">{description}</p>}
</div>
)}
<div className="grid gap-6 sm:grid-cols-2 lg:grid-cols-3">
{testimonials.map((testimonial, index) => (
<Card key={index} className="flex flex-col justify-between">
<CardContent className="pt-6">
<p className="text-sm italic text-muted-foreground">
“{testimonial.quote}”
</p>
<div className="mt-6 flex items-center gap-3">
<Avatar className="h-10 w-10">
{testimonial.avatarUrl && <AvatarImage src={testimonial.avatarUrl} />}
<AvatarFallback className="text-xs">
{getInitials(testimonial.author)}
</AvatarFallback>
</Avatar>
<div>
<p className="text-sm font-semibold">{testimonial.author}</p>
<p className="text-xs text-muted-foreground">
{testimonial.role}
{testimonial.company && `, ${testimonial.company}`}
</p>
</div>
</div>
</CardContent>
</Card>
))}
</div>
</div>
</section>
);
}
Registry Setup
Add the Saastro registry to your components.json:
{
"registries": {
"@saastro": "https://ui.saastro.io/r/{name}.json"
}
}