# Testimonial Wall

> Staggered columns of quotes in mixed tones. Takes quotes of any length.

- **Slug:** `testimonial-wall`
- **Kind:** section · **Category:** Proof
- **Source:** original to Viewership UI
- **Docs page:** https://viewership.ai/design/components/testimonial-wall
- **All files in one bundle:** https://viewership.ai/design/components/testimonial-wall.bundle.txt
- **Structured JSON:** https://viewership.ai/design/components/testimonial-wall.json

## Install

1. Import the foundation tokens once (download: https://viewership.ai/design/raw/foundation.css.txt):

```astro
---
// src/layouts/Layout.astro
import "../styles/foundation.css";
---
```

2. Copy this file into `src/components/viewership/testimonial-wall/`:

   - `TestimonialWall.astro` (raw: https://viewership.ai/design/raw/testimonial-wall/TestimonialWall.astro.txt)

npm packages: none.

## Usage

```astro
---
import TestimonialWall from "../components/viewership/testimonial-wall/TestimonialWall.astro";
---

<TestimonialWall />
```

## Example

The gallery demo, verbatim. Use the import path from Usage instead of `./`.

```astro
---
import TestimonialWall from "./TestimonialWall.astro";
---

<TestimonialWall
  title="Kind"
  accent="words."
  intro="Unedited, from repair tickets and trip reports."
  items={[
    { quote: "The zip failed on day nine of a twelve-day trip. They fixed it in two days and the pack outlasted the season.", name: "Maya Ortiz", role: "Guide" },
    { quote: "Honest weights, to the gram.", name: "Priya Raman", role: "Ultralight blogger" },
    { quote: "We outfit twelve students a year. Nobody has lost a buckle since we switched.", name: "Tom Hendry", role: "Outdoor education lead" },
    { quote: "They asked what went wrong and then actually changed the design.", name: "Lena Voss", role: "Climbing coach" },
    { quote: "It works in sideways rain.", name: "Sam Whitlock", role: "Weekend camper" },
    { quote: "Sent back a ten-year-old pack expecting a refusal. Got it back with new straps and a note from the person who fixed it.", name: "Ruth Adeyemi", role: "Scout leader" },
    { quote: "The resale shop is how I afforded my first proper shell.", name: "Jonah Lee", role: "Student" },
  ]}
/>
```

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `title` | `string` |  | Optional centred headline. |
| `accent` | `string` |  | Closing words of the headline. |
| `intro` | `string` |  | Line under the headline. |
| `items` | `{ quote: string; name: string; role?: string }[]` |  | Quotes. Six to nine fill the wall. |
| `as` | `"h2" \| "h3"` | `"h2"` | Heading element. |

## Source

### `src/components/viewership/testimonial-wall/TestimonialWall.astro`

```astro
---
/**
 * TestimonialWall: staggered columns of quotes in mixed tones. Tolerates
 * quotes of any length; columns follow the section width.
 *
 * @example
 * <TestimonialWall title="Kind" accent="words." items={[{ quote: "...", name: "Lena Voss" }]} />
 */
interface Item {
  quote: string;
  name: string;
  role?: string;
}
interface Props {
  title?: string;
  accent?: string;
  intro?: string;
  items: Item[];
  as?: "h2" | "h3";
  class?: string;
}

const { title, accent, intro, items, as: Heading = "h2", class: className } = Astro.props;
---

<section class:list={["vs-testimonial-wall", className]}>
  <div class="vs-testimonial-wall__inner">
    {
      title && (
        <header class="vs-testimonial-wall__head">
          <Heading class="vs-display vs-testimonial-wall__title">
            {title}
            {accent && <> <em>{accent}</em></>}
          </Heading>
          {intro && <p class="vs-testimonial-wall__intro">{intro}</p>}
        </header>
      )
    }
    <ul class="vs-testimonial-wall__cols">
      {
        items.map((q) => (
          <li class="vs-testimonial-wall__cell">
            <figure>
              <blockquote>
                <p>{q.quote}</p>
              </blockquote>
              <figcaption>
                <span class="vs-testimonial-wall__name">{q.name}</span>
                {q.role && <span class="vs-testimonial-wall__role">{q.role}</span>}
              </figcaption>
            </figure>
          </li>
        ))
      }
    </ul>
  </div>
</section>

<style>
  .vs-testimonial-wall {
    container-type: inline-size;
    background: var(--vs-page);
    color: var(--vs-ink);
    font-family: var(--vs-font-sans);
    font-stretch: var(--vs-font-stretch);
  }
  .vs-testimonial-wall__inner {
    max-width: var(--vs-container);
    margin-inline: auto;
    padding: var(--vs-section-y) var(--vs-gutter);
  }
  .vs-testimonial-wall__head {
    margin-bottom: clamp(28px, 5cqi, 56px);
    text-align: center;
  }
  .vs-testimonial-wall__title {
    font-size: clamp(2rem, 6.5cqi, 4.25rem);
  }
  .vs-testimonial-wall__intro {
    max-width: 30rem;
    margin: 1rem auto 0;
    line-height: 1.55;
    color: var(--vs-ink-2);
  }
  .vs-testimonial-wall__cols {
    margin: 0;
    padding: 0;
    list-style: none;
    column-gap: 14px;
  }
  @container (min-width: 560px) {
    .vs-testimonial-wall__cols {
      columns: 2;
    }
  }
  @container (min-width: 900px) {
    .vs-testimonial-wall__cols {
      columns: 3;
    }
  }
  .vs-testimonial-wall__cell {
    break-inside: avoid;
    margin-bottom: 14px;
  }
  .vs-testimonial-wall figure,
  .vs-testimonial-wall blockquote,
  .vs-testimonial-wall blockquote p {
    margin: 0;
  }
  .vs-testimonial-wall figure {
    padding: 24px;
    border-radius: var(--vs-radius-card);
    background: var(--vs-canvas);
  }
  .vs-testimonial-wall blockquote {
    font-size: 1rem;
    line-height: 1.55;
  }
  .vs-testimonial-wall figcaption {
    display: flex;
    flex-wrap: wrap;
    gap: 2px 8px;
    margin-top: 16px;
    font-size: 0.8125rem;
  }
  .vs-testimonial-wall__name {
    font-weight: 600;
  }
  .vs-testimonial-wall__role {
    color: var(--vs-ink-3);
  }
  .vs-testimonial-wall__cell:nth-child(3n + 2) figure {
    border: var(--vs-border-w) solid var(--vs-line);
    background: var(--vs-surface);
  }
  .vs-testimonial-wall__cell:nth-child(4n) figure {
    background: var(--vs-ink);
    color: var(--vs-ink-inverse);
  }
  .vs-testimonial-wall__cell:nth-child(4n) .vs-testimonial-wall__role {
    color: inherit;
    opacity: 0.6;
  }
  .vs-testimonial-wall__cell:nth-child(5n) figure {
    background: var(--vs-accent-tint);
  }
</style>
```
