1 estrella en GitHub = 1 componente nuevo.

Dar una estrella
Testimonios & Prueba Social

Testimonial Grid Section

Cuadrícula bento de testimonios de clientes con valoraciones de avatar, insignias verificadas y citas.

sectionstestimonialsreviewssocial-proofgrid
Vista Previa en Vivo
WALL OF LOVE

Trusted by thousands of Astro builders

Discover why developers, indie hackers, and creative agencies rely on Astro Components Kit for production websites.

★★★★★
"The pure zero-JS philosophy with React 5 is game-changing. Our Core Web Vitals score hit 100 on every audited route without tweaking hydration."
Elena Rostova
Elena Rostova
Principal Architect @ Veloce Labs
★★★★★
"Copying and pasting self-contained React components directly shaved two full sprints off our SaaS launch timeline."
Marcus Vance
Marcus Vance
Founder @ HyperSync
★★★★★
"The glassmorphic dark palette with gold accents feels extraordinarily premium right out of the box. Highly recommended."
Sofia Chen
Sofia Chen
Senior UI/UX Designer

Uso

Copia y pega este código directamente en tu componente React:

tsx
import { TestimonialGridSection } from 'react-component-kit-ui/sections';

<TestimonialGridSection />

Instalación Manual

Si no estás usando el paquete npm, crea un archivo nuevo y pega el siguiente código: src/components/sections/TestimonialGridSection.tsx + TestimonialGridSection.css:

TestimonialGridSection.tsx
'use client';

import './TestimonialGridSection.css';

/** class:list → className */
function cx(...args: unknown[]): string {
  const out: string[] = [];
  const walk = (v: unknown) => {
    if (!v) return;
    if (typeof v === 'string' || typeof v === 'number') out.push(String(v));
    else if (Array.isArray(v)) v.forEach(walk);
    else if (typeof v === 'object') for (const [k, on] of Object.entries(v as Record<string, unknown>)) if (on) out.push(k);
  };
  args.forEach(walk);
  return out.join(' ');
}

/**
 * TestimonialGridSection — Bento grid showcase of verified customer reviews with dark glass styling and star ratings.
 * 
 * @param {string} eyebrow - Small uppercase category lead. Default is 'WALL OF LOVE'.
 * @param {string} title - Section main headline. Default is 'Trusted by innovative engineering teams'.
 * @param {string} subtitle - Subtitle description.
 */
export interface TestimonialGridSectionProps {
  eyebrow?: string;
  title?: string;
  subtitle?: string;
}

export function TestimonialGridSection({
  eyebrow = 'WALL OF LOVE',
  title = 'Trusted by thousands of Astro builders',
  subtitle = 'Discover why developers, indie hackers, and creative agencies rely on Astro Components Kit for production websites.',
}: TestimonialGridSectionProps) {
  const testimonials = [
    {
      name: 'Elena Rostova',
      role: 'Principal Architect @ Veloce Labs',
      avatar: 'https://images.unsplash.com/photo-1534528741775-53994a69daeb?w=100&auto=format&fit=crop&q=80',
      quote: 'The pure zero-JS philosophy with React 5 is game-changing. Our Core Web Vitals score hit 100 on every audited route without tweaking hydration.',
      stars: 5,
      highlight: true,
    },
    {
      name: 'Marcus Vance',
      role: 'Founder @ HyperSync',
      avatar: 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=100&auto=format&fit=crop&q=80',
      quote: 'Copying and pasting self-contained React components directly shaved two full sprints off our SaaS launch timeline.',
      stars: 5,
    },
    {
      name: 'Sofia Chen',
      role: 'Senior UI/UX Designer',
      avatar: 'https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=100&auto=format&fit=crop&q=80',
      quote: 'The glassmorphic dark palette with gold accents feels extraordinarily premium right out of the box. Highly recommended.',
      stars: 5,
    },
  ];
  return (
    <>
      <section className="testi-section" data-rk-6335bb="">
        <div className="testi-section__header" data-rk-6335bb="">
          <span className="testi-section__eyebrow" data-rk-6335bb="">{eyebrow}</span>
          <h2 className="testi-section__title" data-rk-6335bb="">{title}</h2>
          <p className="testi-section__subtitle" data-rk-6335bb="">{subtitle}</p>
        </div>
      
        <div className="testi-section__grid" data-rk-6335bb="">
          {testimonials.map((t, __i: number) => (
            <article key={__i} className={cx(['testi-card', { 'testi-card--highlight': t.highlight }])} data-rk-6335bb="">
              <div className="testi-card__stars" aria-label={`${t.stars} out of 5 stars`} data-rk-6335bb="">
                {Array.from({ length: t.stars }).map((_, __i: number) => (
                  <span key={__i} data-rk-6335bb="">★</span>
                ))}
              </div>
              <blockquote className="testi-card__quote" data-rk-6335bb="">
                "{t.quote}"
              </blockquote>
              <div className="testi-card__author" data-rk-6335bb="">
                <img src={t.avatar} alt={t.name} className="testi-card__avatar" loading="lazy" data-rk-6335bb="" />
                <div className="testi-card__meta" data-rk-6335bb="">
                  <h5 className="testi-card__name" data-rk-6335bb="">{t.name}</h5>
                  <span className="testi-card__role" data-rk-6335bb="">{t.role}</span>
                </div>
              </div>
            </article>
          ))}
        </div>
      </section>
    </>
  );
}

export default TestimonialGridSection;
TestimonialGridSection.css
/* TestimonialGridSection — ported from astro-component-kit (sections/TestimonialGridSection.astro) */

.testi-section:where([data-rk-6335bb]) {
  padding: var(--sp-12, 3rem) var(--sp-6, 1.5rem);
  max-width: 1200px;
  margin: 0 auto;
  font-family: var(--font-sans, system-ui, sans-serif);
}

.testi-section__header:where([data-rk-6335bb]) {
  text-align: center;
  max-width: 640px;
  margin: 0 auto 3rem auto;
}

.testi-section__eyebrow:where([data-rk-6335bb]) {
  display: inline-block;
  font-size: 0.75rem;
  font-weight: 800;
  letter-spacing: 0.12em;
  color: var(--c-primary-light, #d4a017);
  padding: 0.35rem 0.8rem;
  border: 1px solid color-mix(in srgb, var(--c-primary, #b8860b) 30%, transparent);
  border-radius: var(--r-sm, 8px);
  margin-bottom: 1rem;
  text-transform: uppercase;
}

.testi-section__title:where([data-rk-6335bb]) {
  font-size: clamp(1.8rem, 4vw, 2.8rem);
  font-weight: 900;
  color: var(--c-text-1, #ffffff);
  letter-spacing: -0.03em;
  margin: 0 0 1rem 0;
}

.testi-section__subtitle:where([data-rk-6335bb]) {
  font-size: 0.95rem;
  color: var(--c-text-2, #a3a3a3);
  line-height: 1.6;
  margin: 0;
}

.testi-section__grid:where([data-rk-6335bb]) {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: 1.5rem;
}

.testi-card:where([data-rk-6335bb]) {
  display: flex;
  flex-direction: column;
  padding: var(--sp-8, 2rem);
  background: rgb(var(--ink-rgb, 255 255 255) / 0.02);
  backdrop-filter: blur(16px);
  border: 1px solid rgb(var(--ink-rgb, 255 255 255) / 0.08);
  border-radius: var(--r-xl, 24px);
  transition: transform 0.3s ease, border-color 0.3s ease;
}

.testi-card:hover:where([data-rk-6335bb]) {
  transform: translateY(-4px);
  border-color: color-mix(in srgb, var(--c-primary, #b8860b) 30%, transparent);
}

.testi-card--highlight:where([data-rk-6335bb]) {
  background: radial-gradient(circle at top left, color-mix(in srgb, var(--c-primary, #b8860b) 10%, transparent), rgb(var(--ink-rgb, 255 255 255) / 0.02) 70%);
  border-color: color-mix(in srgb, var(--c-primary, #b8860b) 40%, transparent);
}

.testi-card__stars:where([data-rk-6335bb]) {
  color: #fbbf24;
  font-size: 1rem;
  letter-spacing: 2px;
  margin-bottom: 1rem;
}

.testi-card__quote:where([data-rk-6335bb]) {
  font-size: 0.95rem;
  color: var(--c-text-1, #ffffff);
  line-height: 1.65;
  margin: 0 0 1.5rem 0;
  flex: 1;
  font-style: italic;
}

.testi-card__author:where([data-rk-6335bb]) {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: auto;
}

.testi-card__avatar:where([data-rk-6335bb]) {
  width: 44px;
  height: 44px;
  border-radius: 50%;
  object-fit: cover;
  border: 2px solid color-mix(in srgb, var(--c-primary, #b8860b) 40%, transparent);
}

.testi-card__name:where([data-rk-6335bb]) {
  font-size: 0.92rem;
  font-weight: 700;
  color: var(--c-text-1, #ffffff);
  margin: 0 0 2px 0;
}

.testi-card__role:where([data-rk-6335bb]) {
  font-size: 0.75rem;
  color: var(--c-text-3, #737373);
}