Testimonial wall

테스티모니얼 월

A dense wall of customer quote cards, flowing in rows or filling a grid, to feel like many people already use this.

Also known as: Review wallQuote grid
···
html
<div class="wall">
  <div class="row" id="row1"></div>
  <div class="row rev" id="row2"></div>
</div>
css
.wall{width:min(96%,860px);display:flex;flex-direction:column;gap:clamp(6px,1.5vmin,10px);overflow:hidden;
  -webkit-mask-image:linear-gradient(90deg,transparent,#000 6%,#000 94%,transparent);
  mask-image:linear-gradient(90deg,transparent,#000 6%,#000 94%,transparent)}
.row{display:flex;gap:clamp(6px,1.5vmin,10px);width:max-content;animation:go 22s linear infinite}
.row.rev{animation-direction:reverse}
.qcard{width:clamp(90px,20vmin,190px);background:var(--surface);border:1px solid var(--line);border-radius:10px;
  padding:clamp(6px,1.6vmin,12px);display:flex;flex-direction:column;gap:6%}
.who{display:flex;align-items:center;gap:6px}
.avatar{width:clamp(14px,3vmin,22px);height:clamp(14px,3vmin,22px);border-radius:50%;flex:none;
  display:grid;place-items:center;color:#fff;font-size:clamp(6px,1.2vmin,9px);font-weight:700}
.name{font-size:clamp(7px,1.3vmin,10px);font-weight:700}
.role{font-size:clamp(6px,1.1vmin,8px);color:var(--muted)}
.quote{margin:0;font-size:clamp(6.5px,1.3vmin,10px);color:var(--fg);opacity:.85;line-height:1.35}
@keyframes go{to{transform:translateX(-50%)}}
js
const PEOPLE = [
  ['Sample User 1', 'Placeholder — Ops Lead', 'Cut our weekly report time in half.'],
  ['Sample User 2', 'Placeholder — Founder', 'Set up in an afternoon, no engineer needed.'],
  ['Sample User 3', 'Placeholder — PM', 'The whole team actually uses it daily.'],
  ['Sample User 4', 'Placeholder — Support', 'Tickets dropped 30% after switching.'],
  ['Sample User 5', 'Placeholder — Designer', 'Finally a tool that feels this fast.'],
];
const ACCENTS = ['var(--accent)', 'var(--accent-2)', 'var(--accent-3)'];
function fill(id) {
  const row = document.getElementById(id);
  for (let copy = 0; copy < 2; copy++) {
    PEOPLE.forEach(function (p, i) {
      const card = document.createElement('div');
      card.className = 'qcard';
      const initials = p[0].split(' ').map(function (w) { return w[0]; }).join('');
      card.innerHTML = '<div class="who"><span class="avatar" style="background:' + ACCENTS[i % 3] + '">' +
        initials + '</span><span><span class="name">' + p[0] + '</span><br><span class="role">' + p[1] +
        '</span></span></div><p class="quote">"' + p[2] + '"</p>';
      row.appendChild(card);
    });
  }
}
fill('row1');
fill('row2');

Unlike a single large quote, a testimonial wall packs many short reviews — usually nine to twenty — onto one screen, building trust through sheer volume. Each card pairs an avatar (or initials), a name and role, and a short quote.

Auto-scrolling several rows at different speeds and in alternating directions (top row drifts left, next row drifts right) is a common treatment — it reads far more alive than a static grid.

If every quote is generic praise ("Amazing product!"), the wall starts to feel fabricated. Quotes with a specific number or situation ("cut onboarding from 3 days to 2 hours") earn more trust. Every person shown in this demo is an invented placeholder.

When to use

Use once you have double-digit reviews and want the sense of volume. With only a handful, don't loop them artificially — use a single featured quote instead.