# Testimonial Wall

> A headline over a masonry wall of quote cards, each with a name, role, and avatar, and an optional Show more.

- Name: `testimonial-wall`
- Status: beta
- Categories: testimonials, social proof, marketing
- Files: the install writes `testimonial-wall.tsx`, and any part files named `testimonial-wall-*.tsx`, to your `components` alias, `@/components` by default. Edit them freely. They are yours.
- Other registry items: `@arbokui/avatar`, `@arbokui/button`, `@arbokui/motion-timing`. The install adds them.
- Gallery: https://arbokui.com/website/testimonial-wall
- Registry item: https://arbokui.com/r/testimonial-wall.json

## Install

1. Add the registry to `components.json`. Do this first, once:

   ```bash
   npx shadcn@latest registry add "@arbokui=https://arbokui.com/r/{name}.json"
   ```

   The command writes this entry. You can also add it by hand:

   ```json
   {
     "registries": {
       "@arbokui": "https://arbokui.com/r/{name}.json"
     }
   }
   ```

   Without this step, the shadcn CLI looks up `@arbokui` in a public list that Arbokui does not control.

2. Add the theme once per app. It replaces your color tokens with ones checked for contrast:

   ```bash
   npx shadcn@latest add @arbokui/theme
   ```

3. Add the website component. It also adds every component it uses:

   ```bash
   npx shadcn@latest add @arbokui/testimonial-wall
   ```

## Use it for

- The social proof section of a landing or pricing page, between the features and the FAQ.
- Six to twelve quotes of mixed length. Short and long ones side by side make the wall.
- Give each person a \`role\` that says who they are and where, like "Design lead at a studio".
- Set \`limit\` to six or so when you have many quotes. The rest wait behind Show more.
- Give it a \`title\`, or an aria-label when the section has no headline.
- The headline is set in the theme's \`font-headline\`. Load Geist Serif as \`--font-geist-serif\`, like \`geist/font/serif/variable\` in Next.js, or it falls back to the system serif.

## Avoid it for

- Quotes you made up or edited past what the person said. Ask each one first.
- One or two quotes. Put them in the hero, or in a plain row.
- Star ratings or reviews from a store. Link to the store instead.
- A wall of logos. Use Logo Marquee.

## Props

- `testimonials`: `{ quote: ReactNode; name: string; role?: ReactNode; avatar?: string }[]`. The quotes, in the order to read them. Each name must be unique, since it is the key. avatar is a photo URL. Without one, the initials show.
- `title`: `ReactNode`. The headline's first words, in full ink. It grows with the wall's width, from 28 to 36px.
- `muted`: `ReactNode`. The words that follow the title in a quieter gray, on the same line.
- `description`: `ReactNode`. A line or two under the headline.
- `as`: `"h2" | "h3"`. Default `"h2"`. The headline's level.
- `limit`: `number`. Default `all of them`. Shows this many quotes, then a Show more button for the rest. The bottom of the wall fades while some are hidden. The rest open as a second wall under the first, so no card you already see moves.
- `showMoreLabel`: `string`. Default `"Show more"`. The button's words while quotes are hidden.
- `showLessLabel`: `string`. Default `"Show less"`. The button's words once every quote shows.
- `className`: `string`. Extra classes on the section, which holds the container query. One column when narrow, two from 36rem, three from 64rem.

## Accessibility

- The wall is a list. Each card is a figure: the quote is a blockquote, and the name and role are its caption.
- The avatar is hidden from screen readers, since the name is written beside it.
- Screen readers read the quotes in the order you give them, which runs down the first column, then the next.
- Hidden quotes are not on the page, so screen readers never read a quote people cannot see. Show more adds the rest as a second list under the first.
- Show more is a button with aria-expanded, and aria-controls points at the list. Focus stays on it when it opens or closes.
- In forced colors each card gets a border, and the fade goes away.

## Examples

### Under a headline, with Show more

```tsx
<TestimonialWall
  title="Loved by team leads,"
  muted="and their teams too."
  limit={6}
  testimonials={[
    { name: "Priya Raman", role: "Design lead at a studio", quote: "Now everyone answers in one place." },
    { name: "Tomás Okafor", role: "Office manager at a clinic", quote: "Setup took an afternoon." },
    { name: "Elin Sato", role: "Team lead at a library", quote: "People stopped asking me what time the all-hands is." },
  ]}
/>
```

### With photos and no headline

```tsx
<TestimonialWall
  aria-label="What teams say"
  testimonials={[
    { name: "Priya Raman", role: "Design lead", avatar: "/people/priya.jpg", quote: "Now everyone answers in one place." },
    { name: "Tomás Okafor", role: "Office manager", avatar: "/people/tomas.jpg", quote: "Setup took an afternoon." },
  ]}
/>
```
