Spinning Testimonials
A sleek, reusable testimonial carousel that smoothly spins through any number of testimonials. Designed to be fully responsive, it automatically converts its direct children into carousel slides, making it perfect for highlighting customer feedback in a compact, eye-catching way.
Current Theme:
"This SaaS cut our onboarding time from days to hours, all without messy spreadsheets."
GR
Guillermo Rauch
CEO / Vercel
"The dashboard delivers real-time insights, helping us make faster, smarter decisions."
TB
Theo Browne
CEO / Ping Labs
"We replaced three tools with this one. It’s clean, intuitive, and a joy to use.We replaced three tools with this one. It’s clean, intuitive, and a joy to use."
KCD
Kent C. Dodds
Frontend Educator
"Support is fast, friendly, and the product keeps getting better with each update."
CN
shadcn
Creator of shadcn/ui
API usage
components/spinning-testimonials.demo.tsx
import { SpinningCarousel } from "@/components/spinning-carousel";
import {
TestimonialCard,
TestimonialContent,
TestimonialAvatar,
TestimonialAvatarFallback,
TestimonialAvatarImage,
TestimonialName,
TestimonialPosition,
TestimonialAuthor,
} from "@/components/ui/testimonial";
export function SpinningTestimonialsDemo() {
return (
<SpinningCarousel className="h-[calc(500px_-_30vw)] min-h-60 lg:h-[calc(400px_-_7vw)]">
{TESTIMONIALS.map(({ name, testimonial, position, src, fallback }) => (
<TestimonialCard key={name}>
<TestimonialContent className="-indent-1.5 lg:-indent-2">
"{testimonial}"
</TestimonialContent>
<TestimonialAuthor>
<TestimonialAvatar className="size-10">
<TestimonialAvatarImage src={src} />
<TestimonialAvatarFallback>{fallback}</TestimonialAvatarFallback>
</TestimonialAvatar>
<TestimonialName>{name}</TestimonialName>
<TestimonialPosition>{position}</TestimonialPosition>
</TestimonialAuthor>
</TestimonialCard>
))}
</SpinningCarousel>
);
}
const TESTIMONIALS = [
{
testimonial:
"This SaaS cut our onboarding time from days to hours, all without messy spreadsheets.",
name: "Guillermo Rauch",
position: "CEO / Vercel",
src: "https://github.com/rauchg.png",
fallback: "GR",
},
{
testimonial:
"The dashboard delivers real-time insights, helping us make faster, smarter decisions.",
name: "Theo Browne",
position: "CEO / Ping Labs",
src: "https://github.com/t3dotgg.png",
fallback: "TB",
},
{
testimonial:
"We replaced three tools with this one. It’s clean, intuitive, and a joy to use.We replaced three tools with this one. It’s clean, intuitive, and a joy to use.",
name: "Kent C. Dodds",
position: "Frontend Educator",
src: "https://github.com/kentcdodds.png",
fallback: "KCD",
},
{
testimonial:
"Support is fast, friendly, and the product keeps getting better with each update.",
name: "shadcn",
position: "Creator of shadcn/ui",
src: "https://github.com/shadcn.png",
fallback: "CN",
},
{
name: "Paul Copperstone",
position: "CEO / Supabase",
testimonial:
"Setup took less than a day, and productivity improved immediately across teams.",
src: "https://github.com/kiwicopple.png",
fallback: "PC",
},
];
Installation
CLI (recommended)
1
Run the command below to add the component to your project.
It will also generate the required base stylesheet if one doesn't already exist and guide you through setting up the import alias
@/components/... if it isn't already configured.pnpm dlx shadcn@latest add https://100xui.com/components/spinning-testimonials.jsonManual
1
pnpm add @radix-ui/react-avatar clsx motion tailwind-merge2
100xui
components/spinning-carousel.tsx
3
API reference
<SpinningCarousel/>
| Props | Type | Description | Default value |
|---|---|---|---|
children | | An array of ReactElements to be rendered as individual carousel cards. | |
animationDurationInSec? | | Duration (in seconds) of the transition animation between carousel cards. | |
readTimeInSec? | | Time (in seconds) each card stays visible before moving to the next. This allows the user time to read and view the content. | |
...rest | | Any standard React div props, like id, style or className, which will be applied directly to the component's root element except for ref. | |
<TestimonialCard/><TestimonialContent/><TestimonialAuthor/><TestimonialName/><TestimonialPosition/>
| Props | Type | Description | Default value |
|---|---|---|---|
props | | Any standard React div props, like children, id, style or className, which will be applied directly to the component's root element. | |
<TestimonialAvatar/><TestimonialAvatarImage/><TestimonialAvatarFallback/>
These components wrap shadcn/ui's <Avatar/>, <AvatarImage/>, and <AvatarFallback/>, respectively, applying custom styling for the testimonial layout. See the API reference for details .
Caveats: You need to explicitly set the height of the Set the height at two breakpoints (
<SpinningCarousel/> based on the tallest card to prevent layout shifts when a newly rendered card requires more vertical space than currently available.base: and lg:) as shown in the demo, because the card’s width relative to its parent changes at the lg breakpoint.