Testimonial spotlight
One quote set large and centered, with the name and role underneath.
npx shadcn@latest add https://ui.goodtabs.co/r/testimonial-spotlight.json
With the @goodtabs namespace in components.json: npx shadcn@latest add @goodtabs/testimonial-spotlight
We stopped arguing about buttons. The whole app now looks like one person made it.
One short quote at card size.
With a link
Our designer reviewed the first build and had two comments, both about copy.
A larger line with a case study link in the children slot.
Usage
import { TestimonialSpotlight } from "@/components/testimonial-spotlight"
<TestimonialSpotlight quote="We stopped arguing about buttons." name="Mira Okafor" role="Design engineer" />Props
| Prop | Type | Default | Description |
|---|---|---|---|
| quote | string | The quote, plain text, no quote marks. | |
| name | string | Who said it. | |
| role | string | Their role, one short line. | |
| size | "sm" | "default" | "default" | Quote scale. sm fits a card or narrow column. |
| children | ReactNode | Optional slot under the name, for a link or a logo. |
Source
testimonial-spotlight/testimonial-spotlight.tsx
import * as React from "react";
import { cn } from "@/lib/utils";
type TestimonialSpotlightProps = React.ComponentProps<"figure"> & {
/** The quote, as plain text. No quote marks: the layout says it is a quote. */
quote: string;
/** Who said it. */
name: string;
/** Their role, one short line. */
role?: string;
/** Quote scale. "sm" fits a card or narrow column. */
size?: "sm" | "default";
/** Optional slot under the name, for example a logo or a link to the case study. */
children?: React.ReactNode;
};
const quoteSize = {
sm: "text-lg sm:text-xl",
default: "text-2xl sm:text-3xl lg:text-4xl",
};
/**
* One quote, set large and centered. Use it when a single voice carries a section.
* Server component.
*/
export function TestimonialSpotlight({
quote,
name,
role,
size = "default",
children,
className,
...props
}: TestimonialSpotlightProps) {
return (
<figure
data-slot="testimonial-spotlight"
className={cn("m-0 mx-auto flex max-w-3xl flex-col items-center gap-6 px-4 py-10 text-center", className)}
{...props}
>
<blockquote className={cn("m-0 leading-snug font-medium tracking-tight text-balance", quoteSize[size])}>
{quote}
</blockquote>
<figcaption className="flex flex-col items-center gap-0.5">
<span className="text-sm font-medium text-foreground">{name}</span>
{role && <span className="text-xs text-muted-foreground">{role}</span>}
{children && <div className="mt-3">{children}</div>}
</figcaption>
</figure>
);
}
For AI agents
Hand your agent this page, the markdown at /components/testimonial-spotlight/prompt.md, or the Copy AI prompt button above.
When to use
- One strong voice between two sections
- A case study header
- When a single line carries the argument
When not to use
- Several quotes at once, where a wall fits
- Long paragraphs, which read badly at this size
- Quotes without permission
Agent notes
- Server component, a figure with blockquote and figcaption
- Default size is text-2xl to text-4xl; use sm in cards
- Text is balanced and centered with max-w-3xl
- Demo people are fictional; replace with real, permissioned quotes