Testimonials
Filterable quote grid by industry
Chips narrow the wall to your own sector
Chips narrow the wall to your own sector
Build a filterable testimonial grid with Tailwind CSS. Above the grid, a heading, a muted subline and a row of six filter chips — All, Healthcare, Logistics, Finance, Retail and Public sector — with the active chip dark. The grid holds nine bordered rounded-xl quote cards, three across on large screens: each card has a small industry label at the top, a quote of two or three sentences in relaxed type, and a footer separated by a hairline with an avatar circle, a name in medium weight and a role and company line. Two cards carry a small "Case study" pill linking onward. Then add JavaScript that filters cards by their industry data attribute with a brief fade, keeps a live count in the subline, shows a muted empty line when a filter matches nothing, and restores everything when All is chosen. <section class="mx-auto max-w-6xl px-6 py-16">
<div class="max-w-2xl">
<h2 class="text-3xl font-semibold tracking-tight text-neutral-900">Read the ones that sound like you</h2>
<p class="mt-3 text-neutral-500"><span id="quoteCount">9</span> customers, grouped by the mess they were in before.</p>
</div>
<div id="quoteChips" class="mt-7 flex flex-wrap gap-2">
<button data-filter="all" class="qchip rounded-full bg-neutral-900 px-3.5 py-1.5 text-xs font-medium text-white">All</button>
<button data-filter="health" class="qchip rounded-full border border-neutral-200 px-3.5 py-1.5 text-xs font-medium text-neutral-600 transition hover:bg-neutral-50">Healthcare</button>
<button data-filter="logistics" class="qchip rounded-full border border-neutral-200 px-3.5 py-1.5 text-xs font-medium text-neutral-600 transition hover:bg-neutral-50">Logistics</button>
<button data-filter="finance" class="qchip rounded-full border border-neutral-200 px-3.5 py-1.5 text-xs font-medium text-neutral-600 transition hover:bg-neutral-50">Finance</button>
<button data-filter="retail" class="qchip rounded-full border border-neutral-200 px-3.5 py-1.5 text-xs font-medium text-neutral-600 transition hover:bg-neutral-50">Retail</button>
<button data-filter="public" class="qchip rounded-full border border-neutral-200 px-3.5 py-1.5 text-xs font-medium text-neutral-600 transition hover:bg-neutral-50">Public sector</button>
</div>
<div id="quoteGrid" class="mt-8 grid gap-4 md:grid-cols-2 lg:grid-cols-3">
<article data-industry="health" class="qcard flex flex-col rounded-xl border border-neutral-200 bg-white p-6 transition-opacity">
<p class="text-[11px] font-medium uppercase tracking-widest text-neutral-400">Healthcare</p>
<blockquote class="mt-3 flex-1 leading-relaxed text-neutral-700">"Rota changes used to reach the ward by printout. Now the change lands on eleven phones before the shift starts, and nobody has to trust a laminated sheet."</blockquote>
<div class="mt-5 flex items-center gap-3 border-t border-neutral-100 pt-4">
<span class="grid h-9 w-9 place-items-center rounded-full bg-neutral-900 text-[11px] font-medium text-white">AT</span>
<div><p class="text-sm font-medium text-neutral-900">Aiko Tan</p><p class="text-xs text-neutral-500">Operations Lead · Fernbrook Health</p></div>
</div>
</article>
<article data-industry="logistics" class="qcard flex flex-col rounded-xl border border-neutral-200 bg-white p-6 transition-opacity">
<div class="flex items-center justify-between">
<p class="text-[11px] font-medium uppercase tracking-widest text-neutral-400">Logistics</p>
<a href="#" class="rounded-full bg-neutral-100 px-2 py-0.5 text-[10px] font-medium text-neutral-600">Case study</a>
</div>
<blockquote class="mt-3 flex-1 leading-relaxed text-neutral-700">"Sixty-two depots live in a fortnight. The rollout plan fitted on one page, which is the first time that has ever been true here."</blockquote>
<div class="mt-5 flex items-center gap-3 border-t border-neutral-100 pt-4">
<span class="grid h-9 w-9 place-items-center rounded-full bg-amber-500 text-[11px] font-medium text-white">PM</span>
<div><p class="text-sm font-medium text-neutral-900">Priya Mahal</p><p class="text-xs text-neutral-500">Head of Operations · Kestrel</p></div>
</div>
</article>
<article data-industry="finance" class="qcard flex flex-col rounded-xl border border-neutral-200 bg-white p-6 transition-opacity">
<p class="text-[11px] font-medium uppercase tracking-widest text-neutral-400">Finance</p>
<blockquote class="mt-3 flex-1 leading-relaxed text-neutral-700">"The auditor asked for evidence and I sent one link. Twenty minutes back in everyone's afternoon."</blockquote>
<div class="mt-5 flex items-center gap-3 border-t border-neutral-100 pt-4">
<span class="grid h-9 w-9 place-items-center rounded-full bg-blue-600 text-[11px] font-medium text-white">LR</span>
<div><p class="text-sm font-medium text-neutral-900">Lena Rask</p><p class="text-xs text-neutral-500">Compliance Lead · Oakline</p></div>
</div>
</article>
<article data-industry="retail" class="qcard flex flex-col rounded-xl border border-neutral-200 bg-white p-6 transition-opacity">
<p class="text-[11px] font-medium uppercase tracking-widest text-neutral-400">Retail</p>
<blockquote class="mt-3 flex-1 leading-relaxed text-neutral-700">"Stock figures now match between the shop floor and the warehouse. That sounds small until you have spent three years apologising for it."</blockquote>
<div class="mt-5 flex items-center gap-3 border-t border-neutral-100 pt-4">
<span class="grid h-9 w-9 place-items-center rounded-full bg-green-600 text-[11px] font-medium text-white">HB</span>
<div><p class="text-sm font-medium text-neutral-900">Hana Brandt</p><p class="text-xs text-neutral-500">Retail Systems · Fernbrook Tools</p></div>
</div>
</article>
<article data-industry="public" class="qcard flex flex-col rounded-xl border border-neutral-200 bg-white p-6 transition-opacity">
<p class="text-[11px] font-medium uppercase tracking-widest text-neutral-400">Public sector</p>
<blockquote class="mt-3 flex-1 leading-relaxed text-neutral-700">"Procurement took longer than the implementation, which I am told is the highest praise available in local government."</blockquote>
<div class="mt-5 flex items-center gap-3 border-t border-neutral-100 pt-4">
<span class="grid h-9 w-9 place-items-center rounded-full bg-neutral-500 text-[11px] font-medium text-white">KB</span>
<div><p class="text-sm font-medium text-neutral-900">Karl Bergen</p><p class="text-xs text-neutral-500">Digital Services · Rotterdam</p></div>
</div>
</article>
<article data-industry="finance" class="qcard flex flex-col rounded-xl border border-neutral-200 bg-white p-6 transition-opacity">
<div class="flex items-center justify-between">
<p class="text-[11px] font-medium uppercase tracking-widest text-neutral-400">Finance</p>
<a href="#" class="rounded-full bg-neutral-100 px-2 py-0.5 text-[10px] font-medium text-neutral-600">Case study</a>
</div>
<blockquote class="mt-3 flex-1 leading-relaxed text-neutral-700">"Month-end close went from a three-day slog to a scheduled job. My team stopped dreading the first week of the month."</blockquote>
<div class="mt-5 flex items-center gap-3 border-t border-neutral-100 pt-4">
<span class="grid h-9 w-9 place-items-center rounded-full bg-neutral-900 text-[11px] font-medium text-white">RM</span>
<div><p class="text-sm font-medium text-neutral-900">Rae Mensah</p><p class="text-xs text-neutral-500">Financial Controller · Meridian</p></div>
</div>
</article>
<article data-industry="health" class="qcard flex flex-col rounded-xl border border-neutral-200 bg-white p-6 transition-opacity">
<p class="text-[11px] font-medium uppercase tracking-widest text-neutral-400">Healthcare</p>
<blockquote class="mt-3 flex-1 leading-relaxed text-neutral-700">"Our information governance lead read the data flow diagram and asked no follow-up questions. I have never seen that happen."</blockquote>
<div class="mt-5 flex items-center gap-3 border-t border-neutral-100 pt-4">
<span class="grid h-9 w-9 place-items-center rounded-full bg-amber-500 text-[11px] font-medium text-white">SN</span>
<div><p class="text-sm font-medium text-neutral-900">Sofia Neri</p><p class="text-xs text-neutral-500">IG Manager · Ashgrove Trust</p></div>
</div>
</article>
<article data-industry="logistics" class="qcard flex flex-col rounded-xl border border-neutral-200 bg-white p-6 transition-opacity">
<p class="text-[11px] font-medium uppercase tracking-widest text-neutral-400">Logistics</p>
<blockquote class="mt-3 flex-1 leading-relaxed text-neutral-700">"Drivers see the same numbers as the planners. Half our radio traffic disappeared in the first month."</blockquote>
<div class="mt-5 flex items-center gap-3 border-t border-neutral-100 pt-4">
<span class="grid h-9 w-9 place-items-center rounded-full bg-neutral-900 text-[11px] font-medium text-white">TS</span>
<div><p class="text-sm font-medium text-neutral-900">Tom Silva</p><p class="text-xs text-neutral-500">Transport Manager · Kestrel</p></div>
</div>
</article>
<article data-industry="retail" class="qcard flex flex-col rounded-xl border border-neutral-200 bg-white p-6 transition-opacity">
<p class="text-[11px] font-medium uppercase tracking-widest text-neutral-400">Retail</p>
<blockquote class="mt-3 flex-1 leading-relaxed text-neutral-700">"We deleted an internal tool and two cron jobs nobody wanted to own. That is the whole review."</blockquote>
<div class="mt-5 flex items-center gap-3 border-t border-neutral-100 pt-4">
<span class="grid h-9 w-9 place-items-center rounded-full bg-blue-600 text-[11px] font-medium text-white">RG</span>
<div><p class="text-sm font-medium text-neutral-900">Ravi Gopal</p><p class="text-xs text-neutral-500">Engineering Manager · Vantage</p></div>
</div>
</article>
</div>
<p id="quoteEmpty" class="mt-10 hidden text-center text-sm text-neutral-500">No quotes from that sector yet — ask us and we will introduce you to someone directly.</p>
</section> var chips = Array.prototype.slice.call(document.querySelectorAll(".qchip"));
var cards = Array.prototype.slice.call(document.querySelectorAll(".qcard"));
var count = document.getElementById("quoteCount");
var empty = document.getElementById("quoteEmpty");
function apply(filter) {
var shown = 0;
cards.forEach(function (card) {
var visible = filter === "all" || card.dataset.industry === filter;
card.classList.toggle("hidden", !visible);
if (visible) shown += 1;
});
count.textContent = shown;
empty.classList.toggle("hidden", shown !== 0);
}
chips.forEach(function (chip) {
chip.addEventListener("click", function () {
chips.forEach(function (c) {
var on = c === chip;
c.classList.toggle("bg-neutral-900", on);
c.classList.toggle("text-white", on);
c.classList.toggle("border", !on);
c.classList.toggle("border-neutral-200", !on);
c.classList.toggle("text-neutral-600", !on);
});
apply(chip.dataset.filter);
});
});
apply("all");