Marketing
SocialProofTestimonials
A wall of customer quotes: TestimonialCards stacked in columns that scroll vertically at different speeds, fading out at the top and bottom.
Guidelines#
Use it for the testimonials section of the landing page, under a SectionHeader. TestimonialCard also works alone.
What you provide: testimonials: { id, name, role, img, description }[], where description is a node (a <p>, with the key phrase highlighted; Crew OS's Highlight helper is p-1 py-0.5 font-medium dark:font-semibold text-secondary). Every three testimonials make one column, so give 6 or 9. TestimonialCard takes name, role, img, description and className. Crew OS's customer photos come from randomuser.me, which is unreachable here, so this preview uses generated initials.
Anatomy: 40px side padding, at most 750px tall, overflow-hidden; two columns from md, three from xl. Cards are rounded-xl, bg-accent, 16px padding, a hairline ring and soft shadow (a lighter ring in dark mode), 24px between quote and author. Quote text is text-primary/90, leading-relaxed; the author row has a 32px round photo, the name in font-medium and the role in text-xs text-primary/50. The top and bottom sixth (fifth from md) fade into background.
Behaviour: each column is a vertical Marquee (content repeated four times): 40s for the first, 60s the second, 30s the third. Hovering does not pause it, and there is no reduced-motion branch.
Don't put links in quotes, mix very long and very short quotes, or use fewer than six (columns run out).
Facts#
| Group | Marketing |
|---|---|
| Product | Crew OS |
| Global | window.DigitalCrew.SocialProofTestimonials |
| Source | digitalcrew-orchestrator: components/testimonial-scroll.tsx |
| Import in the app | import { SocialProofTestimonials } from "@/components/testimonial-scroll"; |
API#
TypeScript declarations emitted from components/testimonial-scroll.tsx (the module also exports TestimonialCard, SocialProofTestimonials).
export interface TestimonialCardProps extends React.HTMLAttributes<HTMLDivElement> {
name: string;
role: string;
img?: string;
description: React.ReactNode;
className?: string;
}
export declare const TestimonialCard: ({ description, name, img, role, className, ...props }: TestimonialCardProps) => JSX.Element;
interface Testimonial {
id: string;
name: string;
role: string;
img: string;
description: React.ReactNode;
}
export declare function SocialProofTestimonials({ testimonials, }: {
testimonials: Testimonial[];
}): JSX.Element;Example#
The code of the preview above: plain React.createElement against window.DigitalCrew, with realistic data.
<div id="root" class="p-6"></div>
<script>
(function () {
var h = React.createElement, DC = window.DigitalCrew, I = DC.Icons;
// Self-contained initials avatars (customer photos are remote in Crew OS).
function avatar(name, bg) {
var ini = name.split(" ").map(function (w) { return w[0]; }).join("");
var svg = "<svg xmlns='http://www.w3.org/2000/svg' width='64' height='64'><rect width='64' height='64' fill='" + bg + "'/><text x='32' y='41' font-family='Arial' font-size='24' font-weight='600' fill='white' text-anchor='middle'>" + ini + "</text></svg>";
return "data:image/svg+xml;utf8," + encodeURIComponent(svg);
}
function quote(a, hl, b) { return h("p", null, a, " ", h("span", { className: "font-semibold text-primary" }, hl), " ", b); }
var testimonials = [
{ id: "1", name: "Claire Dubois", role: "CFO at Northwind Traders", img: avatar("Claire Dubois", "#8b5cf6"), description: quote("We handed our finance follow-ups to Max in March.", "Month-end chasing dropped from three days to one afternoon.", "Nobody wants the old way back.") },
{ id: "2", name: "Omar Haddad", role: "VP Finance at Brightline", img: avatar("Omar Haddad", "#0ea5e9"), description: quote("The first week felt like hiring a senior SDR.", "Eleven qualified meetings, zero manual lists.", "Our AEs finally sell all day.") },
{ id: "3", name: "Lena Fischer", role: "Head of Sales at Kestrel Labs", img: avatar("Lena Fischer", "#10b981"), description: quote("Replies are sorted by intent before I open my inbox.", "I only see the conversations worth my time.", "") },
{ id: "4", name: "Marc Lefèvre", role: "Founder at Atlas Freight", img: avatar("Marc Lefèvre", "#f59e0b"), description: quote("We run outbound in three languages with a team of two.", "Follow-ups never slip anymore.", "It just keeps going.") },
{ id: "5", name: "Aiko Tanaka", role: "COO at Vantage Health", img: avatar("Aiko Tanaka", "#ec4899"), description: quote("Sophie screens every applicant the same day.", "Time to first interview went from nine days to two.", "") },
{ id: "6", name: "Julien Moreau", role: "Revenue Ops at Helios Capital", img: avatar("Julien Moreau", "#6366f1"), description: quote("Everything lands in the CRM with the context attached.", "Our pipeline reviews take half the time.", "Clean data, finally.") }
];
function App() { return h(DC.SocialProofTestimonials, { testimonials: testimonials }); }
ReactDOM.createRoot(document.getElementById("root")).render(h(DC.TooltipProvider, { delayDuration: 80 }, h(App)));
})();
</script>