1 GitHub star = 1 new component.

Star the repo
Page Sections sectionstestimonialsreviewssocial-proofgrid

Testimonial Grid Section

High-converting customer review bento grid featuring avatar ratings and verified badges.

Live Preview

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 Astro 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 Astro 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

Usage

Copy and paste this code into your Astro page:

astro
---
import { TestimonialGridSection } from 'astro-component-kit';
---

<TestimonialGridSection />
--- import { TestimonialGridSection } from 'astro-component-kit'; --- <TestimonialGridSection />

Manual Installation

If you are not using the npm package, create a new file and paste the following code: src/components/lib/TestimonialGridSection.astro:

astro
---
/**
 * 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.
 */
interface Props {
  eyebrow?: string;
  title?: string;
  subtitle?: string;
}

const {
  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.',
} = Astro.props;

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 Astro 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 Astro 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,
  },
];
---

<section class="testi-section">
  <div class="testi-section__header">
    <span class="testi-section__eyebrow">{eyebrow}</span>
    <h2 class="testi-section__title">{title}</h2>
    <p class="testi-section__subtitle">{subtitle}</p>
  </div>

  <div class="testi-section__grid">
    {testimonials.map((t) => (
      <article class:list={['testi-card', { 'testi-card--highlight': t.highlight }]}>
        <div class="testi-card__stars" aria-label={`${t.stars} out of 5 stars`}>
          {Array.from({ length: t.stars }).map(() => (
            <span>★</span>
          ))}
        </div>
        <blockquote class="testi-card__quote">
          "{t.quote}"
        </blockquote>
        <div class="testi-card__author">
          <img src={t.avatar} alt={t.name} class="testi-card__avatar" loading="lazy" />
          <div class="testi-card__meta">
            <h5 class="testi-card__name">{t.name}</h5>
            <span class="testi-card__role">{t.role}</span>
          </div>
        </div>
      </article>
    ))}
  </div>
</section>

<style>
  .testi-section {
    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 {
    text-align: center;
    max-width: 640px;
    margin: 0 auto 3rem auto;
  }

  .testi-section__eyebrow {
    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 {
    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 {
    font-size: 0.95rem;
    color: var(--c-text-2, #a3a3a3);
    line-height: 1.6;
    margin: 0;
  }

  .testi-section__grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
    gap: 1.5rem;
  }

  .testi-card {
    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 {
    transform: translateY(-4px);
    border-color: color-mix(in srgb, var(--c-primary, #b8860b) 30%, transparent);
  }

  .testi-card--highlight {
    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 {
    color: #fbbf24;
    font-size: 1rem;
    letter-spacing: 2px;
    margin-bottom: 1rem;
  }

  .testi-card__quote {
    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 {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-top: auto;
  }

  .testi-card__avatar {
    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 {
    font-size: 0.92rem;
    font-weight: 700;
    color: var(--c-text-1, #ffffff);
    margin: 0 0 2px 0;
  }

  .testi-card__role {
    font-size: 0.75rem;
    color: var(--c-text-3, #737373);
  }
</style>
--- /** * 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. */ interface Props { eyebrow?: string; title?: string; subtitle?: string; } const { 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.', } = Astro.props; 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 Astro 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 Astro 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, }, ]; --- <section class="testi-section"> <div class="testi-section__header"> <span class="testi-section__eyebrow">{eyebrow}</span> <h2 class="testi-section__title">{title}</h2> <p class="testi-section__subtitle">{subtitle}</p> </div> <div class="testi-section__grid"> {testimonials.map((t) => ( <article class:list={['testi-card', { 'testi-card--highlight': t.highlight }]}> <div class="testi-card__stars" aria-label={`${t.stars} out of 5 stars`}> {Array.from({ length: t.stars }).map(() => ( <span>★</span> ))} </div> <blockquote class="testi-card__quote"> "{t.quote}" </blockquote> <div class="testi-card__author"> <img src={t.avatar} alt={t.name} class="testi-card__avatar" loading="lazy" /> <div class="testi-card__meta"> <h5 class="testi-card__name">{t.name}</h5> <span class="testi-card__role">{t.role}</span> </div> </div> </article> ))} </div> </section> <style> .testi-section { 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 { text-align: center; max-width: 640px; margin: 0 auto 3rem auto; } .testi-section__eyebrow { 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 { 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 { font-size: 0.95rem; color: var(--c-text-2, #a3a3a3); line-height: 1.6; margin: 0; } .testi-section__grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: 1.5rem; } .testi-card { 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 { transform: translateY(-4px); border-color: color-mix(in srgb, var(--c-primary, #b8860b) 30%, transparent); } .testi-card--highlight { 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 { color: #fbbf24; font-size: 1rem; letter-spacing: 2px; margin-bottom: 1rem; } .testi-card__quote { 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 { display: flex; align-items: center; gap: 12px; margin-top: auto; } .testi-card__avatar { 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 { font-size: 0.92rem; font-weight: 700; color: var(--c-text-1, #ffffff); margin: 0 0 2px 0; } .testi-card__role { font-size: 0.75rem; color: var(--c-text-3, #737373); } </style>

Quick Info

Category
Page Sections
Filename
TestimonialGridSection.astro
Dependencies
None — pure Astro + CSS
Tags
sectionstestimonialsreviewssocial-proofgrid