Testimonial Section
Recently added component.
Preview
Live interactive preview.
Installation
Add this component to your project using the CLI:
terminal
npx -y vui-registry-cli-v1@latest add testimonial-sectionSource Code
rich-testimonial-section.tsx
"use client";
import React, { useRef, useState } from "react";
import { motion, useScroll, useTransform, AnimatePresence } from "framer-motion";
import Image from "next/image";
const testimonials = [
{
name: "Alex Rivera",
role: "Frontend Architect",
text: "Velocity UI didn't just speed up our workflow; it completely redefined our standard for quality. The components feel truly premium out of the box.",
avatar: "https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=150&h=150&fit=crop&crop=faces"
},
{
name: "Priya Sharma",
role: "Design Lead",
text: "As a designer, I'm extremely picky about typography and spacing. This is the first UI kit I've used that gets the microscopic details exactly right.",
avatar: "https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=150&h=150&fit=crop&crop=faces"
},
{
name: "Jordan Lee",
role: "Indie Hacker",
text: "Shipped my SaaS in a weekend. The dark mode implementation and glassmorphic details make it look like I had a full design team.",
avatar: "https://images.unsplash.com/photo-1500648767791-00dcc994a43e?w=150&h=150&fit=crop&crop=faces"
}
];
export default function RichTestimonialSection() {
const containerRef = useRef<HTMLDivElement>(null);
const [hoveredIdx, setHoveredIdx] = useState<number | null>(null);
const { scrollYProgress } = useScroll({
target: containerRef,
offset: ["start end", "end start"]
});
const y1 = useTransform(scrollYProgress, [0, 1], [40, -40]);
const y2 = useTransform(scrollYProgress, [0, 1], [80, -80]);
return (
<section ref={containerRef} className="relative w-full bg-background py-32 overflow-hidden selection:bg-foreground selection:text-background">
<div className="max-w-7xl mx-auto px-6 relative z-20">
{/* Header */}
<div className="flex flex-col items-start mb-24">
<motion.div
initial={{ opacity: 0, x: -20 }}
whileInView={{ opacity: 1, x: 0 }}
viewport={{ once: true }}
className="flex items-center gap-4 mb-6"
>
<div className="w-8 h-[1px] bg-foreground/30" />
<span className="text-[10px] font-bold uppercase tracking-[0.2em] text-muted-foreground">
Social Proof
</span>
</motion.div>
<motion.h2
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ delay: 0.1 }}
className="text-4xl md:text-6xl font-bold tracking-tighter text-foreground max-w-3xl leading-[1.1]"
>
Loved by the best <br />
<span className="text-muted-foreground font-medium">engineering teams.</span>
</motion.h2>
</div>
{/* Testimonials Grid */}
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
{testimonials.map((t, idx) => (
<motion.div
key={idx}
style={{ y: idx === 1 ? y2 : y1 }}
onMouseEnter={() => setHoveredIdx(idx)}
onMouseLeave={() => setHoveredIdx(null)}
className="relative group cursor-crosshair"
>
<div className="relative bg-card dark:bg-[#0A0A0A] p-8 h-full flex flex-col justify-between transition-all duration-500">
{/* Corner Crosshairs */}
<div className="absolute top-0 left-0 w-2 h-2 border-t border-l border-foreground/20 -translate-x-[1px] -translate-y-[1px]" />
<div className="absolute top-0 right-0 w-2 h-2 border-t border-r border-foreground/20 translate-x-[1px] -translate-y-[1px]" />
<div className="absolute bottom-0 left-0 w-2 h-2 border-b border-l border-foreground/20 -translate-x-[1px] translate-y-[1px]" />
<div className="absolute bottom-0 right-0 w-2 h-2 border-b border-r border-foreground/20 translate-x-[1px] translate-y-[1px]" />
{/* Border that fills on hover */}
<div className="absolute inset-0 border border-border transition-colors duration-500 group-hover:border-foreground/20" />
<div className="relative z-10">
<div className="flex justify-between items-start mb-8">
<svg className="w-6 h-6 text-foreground/20 group-hover:text-foreground transition-colors duration-500" fill="currentColor" viewBox="0 0 24 24">
<path d="M14.017 21v-7.391c0-5.704 3.731-9.57 8.983-10.609l.995 2.151c-2.432.917-3.995 3.638-3.995 5.849h4v10h-9.983zm-14.017 0v-7.391c0-5.704 3.748-9.57 9-10.609l.996 2.151c-2.433.917-3.996 3.638-3.996 5.849h3.983v10h-9.983z" />
</svg>
<span className="text-[9px] font-mono text-muted-foreground uppercase tracking-widest">
ID_0{idx + 1}
</span>
</div>
<p className="text-foreground text-lg leading-relaxed tracking-tight mb-8 font-medium">
"{t.text}"
</p>
</div>
<div className="relative z-10 flex items-center gap-4 pt-6 border-t border-border/50">
<div className="relative w-10 h-10 overflow-hidden">
<Image
src={t.avatar}
alt={t.name}
fill
className="object-cover grayscale group-hover:grayscale-0 group-hover:scale-110 transition-all duration-700 ease-out"
/>
</div>
<div>
<h4 className="text-sm font-bold text-foreground">{t.name}</h4>
<p className="text-[10px] font-bold text-muted-foreground uppercase tracking-widest mt-1">{t.role}</p>
</div>
</div>
</div>
</motion.div>
))}
</div>
</div>
</section>
);
}
Props
Component property reference.
| Name | Type | Default | Description |
|---|---|---|---|
| data | Testimonial[] | allTestimonials | Array of testimonial objects to display in the section. |
Context Worth Keeping In Orbit
Most components here are inspired by outstanding libraries and creators in the ecosystem. I don’t claim to be the original author — this is my space for learning, rebuilding, and understanding great work at a deeper level.
I’m still a student of the craft, constantly studying the best and translating what I learn through my own perspective. Every piece reflects curiosity, respect for the community, and small creative touches that feel true to me.
I’ve done my best to credit inspirations properly. If anything is missing or inaccurate, I truly appreciate a message so it can be corrected with care.