Testimonials block
BlockCustomer quotes that carry a real role and a measurable outcome, set still and readable.
pnpm dlx shadcn@latest add https://caliperui.site/r/testimonials-block.jsonWhat controllers say
We closed September in three hours. The team spent the rest of the week on forecasting, which is the job we were hired for.
- 3h
- month-end close, down from 9 days
- −62%
- audit fieldwork hours
“Our auditors sampled the export.”
Lena BrandtCFO, Lumen Labs
When to use #
Use it for
- You have named customers willing to be quoted with a result.
- Proof needs a human voice next to the numbers.
Skip it when
- Anonymous praise; leave it out.
- A rotating marquee; quotes must be readable at rest.
Installation #
terminal
pnpm dlx shadcn@latest add https://caliperui.site/r/testimonials-block.json
Adds its 4 files to components/ui/, each with its own stylesheet, and installs their packages. No account needed. The first part also adds Caliper UI’s tokens; import them once as in Installation.
Usage #
This is the code behind the preview above.
example.tsx
import { type ReactNode } from "react" import { TeamBlock } from "@/components/ui/team-block" import { TestimonialsBlock } from "@/components/ui/testimonials-block" function Frame({ children }: { children: ReactNode }) { return <div className="w-full overflow-hidden rounded-[14px] shadow-[0_0_0_1px_var(--border)]">{children}</div>; } const quotes: Parameters<typeof TestimonialsBlock>[0] = { title: "What controllers say", quotes: [ { quote: "We closed September in three hours. The team spent the rest of the week on forecasting, which is the job we were hired for.", name: "Ana Reyes", role: "Financial controller, Ostra Freight", outcome: { value: "3h", label: "month-end close, down from 9 days" } }, { quote: "Our auditors sampled the export.", name: "Lena Brandt", role: "CFO, Lumen Labs", outcome: { value: "−62%", label: "audit fieldwork hours" } }, ] }; export function TestimonialBlockDemo() { return <Frame><TestimonialsBlock {...quotes} /></Frame>; } const team: Parameters<typeof TeamBlock>[0] = { eyebrow: "Team", title: "The people behind your close", lead: "Write to any of us directly. A person answers.", footnote: "14 people in Lisbon and London. We are hiring a second support lead.", people: [ { name: "Priya Raman", role: "Co-founder", owns: "owns the matching engine", contact: { label: "priya@halden.app", href: "mailto:priya@halden.app" } }, { name: "Rafael Abreu", role: "Head of support", owns: "answers in under 2h", contact: { label: "help@halden.app", href: "mailto:help@halden.app" } }, { name: "Kiara Murayama", role: "Security", owns: "SOC 2, DPAs, pen tests", contact: { label: "security@halden.app", href: "mailto:security@halden.app" } }, { name: "Tomás Ferreira", role: "Accountant in residence", owns: "CPA", contact: { label: "tomas@halden.app", href: "mailto:tomas@halden.app" } }, ] };
API reference #
TestimonialsBlock
component
PropTypeDefaultDescription
titlestring—
quotes *readonly BlockQuote[]—
ratingstring—A sourced rating line, e.g. "4.8 out of 5 from 1,212 reviews on Trustpilot, October 2026".
classNamestring—
Accessibility #
It is built on native elements and keeps aria-hidden in step with state.
No custom key handling; Tab and the native activation keys do the work.
Motion #
It declares no animation in its component source. Any transition comes from its stylesheet, which uses the duration tokens that collapse to instant under prefers-reduced-motion.