Heading and description above a three-column grid of six muted quote cards, each with a short quote, a greyscale Cloud Shape avatar, name and role.
import { Heading } from "@/components/editorial/heading"
import {
Quote,
QuoteAuthor,
QuoteAuthorAvatar,
QuoteAuthorName,
QuoteAuthorRole,
QuoteFigure,
QuoteGroup,
} from "@/components/editorial/quote"
import {
Section,
SectionContent,
SectionDescription,
SectionHeader,
SectionTitleGroup,
} from "@/components/editorial/section"
import {
CloudShape,
type CloudPalette,
} from "@/components/graphics/cloud-shapes"
// The copy: change text here, not in the markup.
const COPY = {
title: "What our customers are saying",
body: "Six teams that moved their support desk to Orbcore this year.",
} as const
const TESTIMONIALS = [
{
body: "Orbcore put every conversation in one queue. For the first time the whole team can see what is waiting and who has it.",
author: { name: "Mae Jemison", role: "Head of Support, Zaira" },
},
{
body: "We wrote each answer once in the knowledge base. Replies that took ten minutes now take one.",
author: { name: "Sally Ride", role: "Founder, Isidora" },
},
{
body: "Routing sends billing questions to billing and bugs to engineering. Nobody forwards a ticket by hand any more.",
author: { name: "Kalpana Chawla", role: "Operations Lead, Despina" },
},
{
body: "The response targets made the slow days visible. We fixed the rota in a week and kept it fixed.",
author: { name: "Peggy Whitson", role: "Support Manager, Zobeide" },
},
{
body: "Our customers noticed before we did. The same people stopped writing in twice about the same order.",
author: { name: "Christina Koch", role: "CEO, Armilla" },
},
{
body: "Reporting answers the questions our board used to ask in every meeting, so they stopped asking.",
author: { name: "Jessica Watkins", role: "COO, Octavia" },
},
] as const
// Knob: the orb's shading; zero chroma keeps it greyscale.
const ORB: CloudPalette = {
main: "oklch(0.55 0 0)",
accent: "oklch(0.7 0 0)",
}
export default function TestimonialGrid01() {
return (
<Section>
<SectionHeader>
<SectionTitleGroup>
<Heading>{COPY.title}</Heading>
</SectionTitleGroup>
<SectionDescription>{COPY.body}</SectionDescription>
</SectionHeader>
<SectionContent>
<QuoteGroup cols={3} className="gap-(--tile-gap)">
{TESTIMONIALS.map((testimonial) => (
<QuoteFigure key={testimonial.author.name} variant="muted">
<Quote>
<p>{testimonial.body}</p>
</Quote>
<QuoteAuthor>
<QuoteAuthorAvatar>
<CloudShape palette={ORB} width={48} height={48} />
</QuoteAuthorAvatar>
<QuoteAuthorName>{testimonial.author.name}</QuoteAuthorName>
<QuoteAuthorRole>{testimonial.author.role}</QuoteAuthorRole>
</QuoteAuthor>
</QuoteFigure>
))}
</QuoteGroup>
</SectionContent>
</Section>
)
}
pnpm dlx shadcn add @01orbital/testimonial-grid-01npx shadcn add @01orbital/testimonial-grid-01yarn shadcn add @01orbital/testimonial-grid-01bunx --bun shadcn add @01orbital/testimonial-grid-01Free under the MIT license. Add the @01orbital registry to components.json once (install guide), then run the command.
It lands at components/blocks/testimonials/testimonial-grid-01/index.tsx, as source you own and edit.
import TestimonialGrid01 from "@/components/blocks/testimonials/testimonial-grid-01"
export default function Example() {
return <TestimonialGrid01 />
}Registry pieces it installs with it:
Split Testimonial with Cover Art
Single testimonial beside a square Celestograph cover in an outlined frame: the art in the narrow column, a large quote with name and role in the wide one.
Compare
Every Timeline block side by side: whether it follows the theme or stays dark, the stock parts it is built on, and whether it is free. Open one for its preview, props and install.