caliper uidocs

Testimonials block

Block

Customer quotes that carry a real role and a measurable outcome, set still and readable.

Installs components/ui/testimonials-block.tsxDepends on lucide-reactMotion none in component source
pnpm dlx shadcn@latest add https://caliperui.site/r/testimonials-block.json

What 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.
Ana ReyesFinancial controller, Ostra Freight
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.