Beste UI Components
componentbadge14source: ok · hit
Testimonial Badge
A testimonial badge with an avatar stack, star rating, and social proof text for hero sections.
npx shadcn add "https://ui.beste.co/component/r/badge14.json"free
No selection tags yet — empty means no evidence, not lack of support.
Dependencies
Bundle weight · lightclsxtailwind-mergelucide-react
Files1 · source cached 10/9/2026, 7:22:13 AM
registry-components/badge14/badge14.tsx
import { Star } from "lucide-react";
import { cn } from "@/lib/utils";
type Tone = "amber" | "primary" | "foreground";
interface Badge14Props {
/** Avatar image URLs, rendered as an overlapping stack */
avatars: string[];
/** The social-proof line (e.g. "Loved by 2,400+ founders") */
text: string;
/** Star count, 0–5 */
rating?: number;
/** Star color */
tone?: Tone;
/** Additional classes merged onto the root */
className?: string;
}
const toneStyles: Record<Tone, string> = {
amber: "text-amber-400",
primary: "text-primary",
foreground: "text-foreground",
};
export const badge14Demo: Badge14Props = {
avatars: [
"https://i.pravatar.cc/64?img=12",
"https://i.pravatar.cc/64?img=32",
"https://i.pravatar.cc/64?img=45",
"https://i.pravatar.cc/64?img=8",
],
text: "Loved by 2,400+ founders",
};
/** Avatar stack + star row + social-proof line, the classic hero trust badge. */
export function Badge14({
avatars,
text,
rating = 5,
tone = "amber",
className,
}: Badge14Props) {
const filled = Math.round(Math.min(Math.max(rating, 0), 5));
return (
<span className={cn("inline-flex w-fit items-center gap-3", className)}>
<span className="flex -space-x-2">
{avatars.map((src) => (
<img
key={src}
src={src}
alt=""
width={32}
height={32}
className="size-8 rounded-full border-2 border-background object-cover"
/>
))}
</span>
<span className="flex flex-col gap-0.5">
<span
className="flex items-center gap-0.5"
role="img"
aria-label={`Rated ${rating} out of 5`}
>
{Array.from({ length: 5 }, (_, i) => (
<Star
// biome-ignore lint/suspicious/noArrayIndexKey: fixed-length decorative row
key={i}
aria-hidden="true"
className={cn(
"size-3.5",
i < filled ? cn("fill-current", toneStyles[tone]) : "text-muted-foreground/30"
)}
/>
))}
</span>
<span className="text-sm text-muted-foreground">{text}</span>
</span>
</span>
);
}