BetaUnder active development — content may be incomplete or change without notice.
A section with left-aligned header and two testimonials with star ratings.
Testimonial 3 is a section with a left-aligned header and description at the top, followed by two testimonials in a 2-column grid (stacks on mobile). Each testimonial includes a star rating, quote, avatar, name, position, and company logo separated by a vertical divider.
| Field Name | Type | Required | Localized | Description |
|---|---|---|---|---|
header | text | Yes | Yes | The main header text for the testimonials section. |
description | richtext | No | Yes | A description or subtitle for the testimonials section. |
testimonials | array | Yes | Yes | An array of 1-2 testimonial items. |
testimonials.quote | richtext | Yes | Yes | The testimonial quote text. |
testimonials.avatar | upload | No | No | Author's avatar image referencing the media collection. |
testimonials.name | text | Yes | Yes | The author's name. |
testimonials.position | text | No | Yes | The author's position and company name. |
testimonials.logo | upload | No | No | Company logo image referencing the media collection. |
testimonials.rating | number | No | No | Star rating from 1-5 (defaults to 5). |
//@ts-nocheck
import React from 'react'
import { Star, Image as ImageIcon } from "lucide-react"
import RichText from '@/components/cms/RichText'
import { Testimonial3Type } from '@/payload-types'
const Testimonial3Component: React.FC<Testimonial3Type> = ({ header, description, testimonials }: Testimonial3Type) => {
const StarRating = ({ rating = 5 }: { rating?: number }) => (
<div className="flex gap-1 mb-4">
{[...Array(5)].map((_, i) => (
<Star
key={i}
className={`w-5 h-5 ${i < rating ? 'fill-foreground text-foreground' : 'fill-muted text-muted'}`}
/>
))}
</div>
)
return (
<section className="w-full min-h-screen bg-background py-16 px-6 md:py-24 lg:py-32">
<div className="container mx-auto flex flex-col items-start">
{/* Section Header - Left Aligned */}
<div className="mb-16 md:mb-20 max-w-2xl text-left">
<h1 className="text-4xl md:text-5xl font-semibold tracking-tight text-foreground mb-6">
{header}
</h1>
{description && (
<RichText
data={description}
enableGutter={false}
className="mx-0 [&_p]:text-muted-foreground [&_p]:text-lg"
/>
)}
</div>
{/* Testimonials Grid */}
<div className="grid grid-cols-1 lg:grid-cols-2 gap-12 lg:gap-16 w-full">
{testimonials?.map((testimonial, index) => (
<div key={index} className="flex flex-col items-start text-left gap-6">
<StarRating rating={testimonial.rating ?? 5} />
{/* Quote */}
<blockquote className="text-lg md:text-xl font-semibold leading-relaxed text-foreground mx-0">
<RichText
data={testimonial.quote}
enableGutter={false}
className="[&_p]:text-lg [&_p]:md:text-xl [&_p]:font-semibold [&_p]:leading-relaxed [&_p]:text-foreground"
/>
</blockquote>
{/* User Info */}
<div className="flex items-center gap-4 pt-2">
{/* Avatar */}
<div className="w-12 h-12 rounded-full bg-muted flex items-center justify-center border border-border overflow-hidden">
{testimonial.avatar && typeof testimonial.avatar === 'object' && testimonial.avatar.url ? (
<img
src={testimonial.avatar.url}
alt={testimonial.avatar.alt || testimonial.name}
className="w-full h-full object-cover"
/>
) : (
<ImageIcon className="w-5 h-5 text-muted-foreground/40" />
)}
</div>
<div className="flex items-center gap-4 h-10">
<div>
<cite className="not-italic font-semibold text-foreground text-sm block">
{testimonial.name}
</cite>
{testimonial.position && (
<p className="text-muted-foreground text-xs">
{testimonial.position}
</p>
)}
</div>
{/* Vertical Divider */}
{testimonial.logo && typeof testimonial.logo === 'object' && testimonial.logo.url && (
<>
<div className="w-[1px] h-full bg-border" />
{/* Logo */}
<a
href="#"
className="transition-opacity hover:opacity-80"
>
<img
src={testimonial.logo.url}
alt={testimonial.logo.alt || 'Company Logo'}
style={{ width: '120px' }}
className="h-auto object-contain dark:invert"
/>
</a>
</>
)}
</div>
</div>
</div>
))}
</div>
</div>
</section>
)
}
export default Testimonial3Component
Build Faster with Blok0 ProBlok0 - PayloadCMS
Follow the journey, request new blocks, and stay updated with the latest releases for Blok0 Payload CMS.
First look at new blocks