All components

Testimonial Basic

Testimonial Basic is a React and Tailwind CSS layout component from UI Layouts, licensed MIT. Copy it and paste it into your project.

UI Layouts MIT layout

What it is

Testimonial Basic is a React and Tailwind CSS layout component from UI Layouts, licensed MIT. Copy it and paste it into your project.

How to use it

Open it in the catalogue, press copy, and paste it into your project. The prompt you copy carries the code and the rules that tell your agent to reproduce it without changing anything.

Open in the catalogue

Five free copies a month. No card.

Needs

npm i motion

Licence

This component comes from UI Layouts and is redistributed under the MIT licence, which permits commercial use. The copyright notice travels with the code.

Testimonial Basic

../../packages/blocks/src/testimonial-section/testimonial-basic.tsx
import React from 'react'
import { cn } from '@/lib/utils'
import { Star } from 'lucide-react'

const TESTIMONIALS = [
  {
    name: 'Beverley',
    role: 'Co-Founder NYZ',
    image: 'https://picsum.photos/seed/beverley/100/100',
    quote:
      "Joining the program dramatically improved my writing skills and thought leadership, resulting in a notable increase in inbound leads. It's a life-changing experience.",
    rating: 5,
    videoThumbnail: 'https://picsum.photos/seed/testimonial-video/1200/675',
  },
  {
    name: 'Marcus Aurelius',
    role: 'Founder Stoic Mind',
    image: 'https://picsum.photos/seed/marcus/100/100',
    quote:
      "Lara's frameworks for personal branding are unparalleled. In six months, we've seen engagement rates triple across our primary social channels.",
    rating: 5,
    videoThumbnail: 'https://picsum.photos/seed/testimonial2/1200/675',
  },
  {
    name: 'Sarah Jenkins',
    role: 'CEO GrowthLab',
    image: 'https://picsum.photos/seed/sarah/100/100',
    quote:
      "The clarity and depth of the mentorship provided exceeded all expectations. It's not just about numbers; it's about building a sustainable legacy.",
    rating: 5,
    videoThumbnail: 'https://picsum.photos/seed/testimonial3/1200/675',
  },
]

export const TestimonialBasic = () => {
  return (
    <section className="bg-white text-black font-dmSans py-24 px-6 md:px-12 lg:px-24">
      <div className="max-w-7xl mx-auto border-x border-neutral-200">
        <div className="text-center mb-24">
          <div className="inline-flex items-center gap-2 text-sm text-nuetral-400 font-semibold uppercase tracking-widest">
            « Testimonials »
          </div>
          <h2 className="text-5xl md:text-7xl font-black text-nuetral-900 tracking-tighter uppercase">
            Social Proof.
          </h2>
        </div>
        {TESTIMONIALS.map((t, i) => (
          <div
            key={i}
            className={cn(
              'grid grid-cols-1 lg:grid-cols-12  border-y border-neutral-200',
              i % 2 === 1 && 'lg:direction-rtl'
            )}
          >
            <div className="lg:col-span-7 p-6 bg-neutral-100 overflow-hidden aspect-video relative group cursor-pointer">
              <div className="absolute pointer-events-none bottom-0 left-0 right-0 top-0 bg-[repeating-linear-gradient(45deg,#eeeeee_0px_1px,transparent_1px_8px)] "></div>

              <img
                src={t.videoThumbnail}
                className="w-full h-full relative z-10 object-cover transition-transform duration-300 rounded-2xl"
                alt={`Testimonial Video ${i}`}
              />
              <div className="absolute bottom-8 left-8 z-10 bg-black/50 backdrop-blur px-6 py-3 rounded-2xl border border-white/20">
                <span className="text-white font-mono text-sm tracking-tighter">
                  04:32 // HD_PLAYBACK
                </span>
              </div>
            </div>

            <div className="lg:col-span-5 border-l border-neutral-200">
              <div className="flex gap-2 items-center border-b p-2 bg-neutral-50 border-neutral-200 relative">
                <div className="absolute pointer-events-none  bottom-0 left-0 right-0 top-0 bg-[repeating-linear-gradient(45deg,#eeeeee_0px_1px,transparent_1px_8px)] "></div>
                <div className="relative z-10 size-16 rounded-3xl overflow-hidden bg-neutral-200 border-4 border-violet-50">
                  <img
                    src={t.image}
                    alt={t.name}
                    className="w-full h-full object-cover"
                  />
                </div>
                <div className="relative z-10">
                  <h4 className="text-2xl font-black uppercase tracking-tight text-nuetral-900">
                    {t.name}
                  </h4>
                  <p className="text-sm font-mono text-nuetral-500 uppercase tracking-widest">
                    {t.role}
                  </p>
                </div>
              </div>
              <div className="p-4">
                <p className="text-3xl font-medium text-nuetral-800 font-manrope">
                  "{t.quote}"
                </p>

                <div className="flex gap-2 mt-4">
                  {[...Array(t.rating)].map((_, i) => (
                    <span key={i} className="text-lg">
                      <Star className="fill-yellow-400 stroke-yellow-400 size-6" />
                    </span>
                  ))}
                </div>
              </div>
            </div>
          </div>
        ))}
      </div>
    </section>
  )
}
./components/ui/timeline-animation.tsx
import type { Variants } from 'motion/react';
import { type HTMLMotionProps, motion, useInView } from 'motion/react';
import type React from 'react';

type TimelineContentProps<T extends keyof HTMLElementTagNameMap> = {
  children?: React.ReactNode;
  animationNum: number;
  className?: string;
  timelineRef: React.RefObject<HTMLElement | null>;
  as?: T;
  customVariants?: Variants;
  once?: boolean;
} & HTMLMotionProps<T>;

export const TimelineAnimation = <T extends keyof HTMLElementTagNameMap = 'div'>({
  children,
  animationNum,
  timelineRef,
  className,
  as,
  customVariants,
  once = true,
  ...props
}: TimelineContentProps<T>) => {
  const defaultSequenceVariants = {
    visible: (i: number) => ({
      filter: 'blur(0px)',
      y: 0,
      opacity: 1,
      transition: {
        delay: i * 0.5,
        duration: 0.5,
      },
    }),
    hidden: {
      filter: 'blur(20px)',
      y: 0,
      opacity: 0,
    },
  };

  const sequenceVariants = customVariants || defaultSequenceVariants;

  const isInView = useInView(timelineRef, {
    once,
  });

  const MotionComponent = motion[as || 'div'] as React.ElementType;

  return (
    <MotionComponent
      initial='hidden'
      animate={isInView ? 'visible' : 'hidden'}
      custom={animationNum}
      variants={sequenceVariants}
      className={className}
      {...props}
    >
      {children}
    </MotionComponent>
  );
};

Similar components