Build a voice-note testimonial player with Tailwind CSS. Include customer identity, company context, play/pause control, waveform, duration, playback progress, speed control, a highlighted quote, and an expandable transcript. Add JavaScript that simulates playback, updates progress and elapsed time, changes playback speed, and opens or closes the transcript with accurate aria-expanded state.
Paste it into Claude, Cursor, v0 or any AI coding tool. Prefer the
finished markup? .
Build a voice-note testimonial player with Tailwind CSS. Include customer identity, company context, play/pause control, waveform, duration, playback progress, speed control, a highlighted quote, and an expandable transcript. Add JavaScript that simulates playback, updates progress and elapsed time, changes playback speed, and opens or closes the transcript with accurate aria-expanded state.
<div class="mx-auto max-w-2xl p-6"><figure class="rounded-3xl bg-neutral-950 p-6 text-white shadow-xl"><div class="flex items-center gap-4"><span class="flex h-12 w-12 items-center justify-center rounded-full bg-cyan-200 text-sm font-semibold text-neutral-900">LN</span><figcaption class="flex-1"><p class="font-medium">Lea Novak</p><p class="text-xs text-white/45">COO at Common Thread · 86 people</p></figcaption><span class="rounded-full border border-white/10 px-3 py-1 text-xs text-white/45">Verified customer</span></div><blockquote class="mt-7 text-2xl font-medium leading-snug tracking-tight">“We stopped asking where the work stood. The answer was already visible.”</blockquote><div class="mt-7 rounded-2xl bg-white/5 p-4"><div class="flex items-center gap-4"><button id="voiceTestPlay" class="flex h-11 w-11 shrink-0 items-center justify-center rounded-full bg-cyan-300 text-neutral-950" aria-label="Play testimonial"><svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" class="inline-block h-[1em] w-[1em] shrink-0 align-[-0.125em] transition-transform"><path d="m9 7 9 5-9 5V7Z" fill="currentColor" stroke="none"/></svg></button><div class="min-w-0 flex-1"><div id="voiceTestWave" class="flex h-9 items-center gap-1"></div><div class="mt-2 flex justify-between font-mono text-[10px] text-white/40"><span id="voiceTestTime">0:00</span><span>0:38</span></div></div><button id="voiceTestSpeed" class="rounded-lg border border-white/10 px-2 py-1 text-xs text-white/60">1×</button></div></div><button id="voiceTranscriptToggle" aria-expanded="false" class="mt-4 text-xs font-medium text-cyan-300">Read transcript</button><div id="voiceTestTranscript" class="mt-3 hidden border-l border-white/15 pl-4 text-sm leading-6 text-white/55">Before Northstar, weekly planning meant stitching together four different reports. Now the operating picture is current before the meeting starts, and the team spends that hour making decisions.</div></figure></div>
var play = document.getElementById("voiceTestPlay"); var speedButton = document.getElementById("voiceTestSpeed"); var wave = document.getElementById("voiceTestWave"); var elapsed = 0; var speed = 1; var timer; for (var i = 0; i < 44; i += 1) { var bar = document.createElement("span"); bar.className = "w-1 rounded-full bg-white/20"; bar.style.height = 8 + (i * 13) % 28 + "px"; wave.appendChild(bar); } function paintTestimonial() { [].slice.call(wave.children).forEach(function (bar, index) { bar.className = "w-1 rounded-full " + (index / wave.children.length <= elapsed / 38 ? "bg-cyan-300" : "bg-white/20"); }); document.getElementById("voiceTestTime").textContent = "0:" + String(Math.floor(elapsed)).padStart(2, "0"); } play.addEventListener("click", function () { if (timer) { clearInterval(timer); timer = null; play.textContent = "▶"; return; } play.textContent = "Ⅱ"; timer = setInterval(function () { elapsed += 0.25 * speed; if (elapsed >= 38) { elapsed = 0; clearInterval(timer); timer = null; play.textContent = "▶"; } paintTestimonial(); }, 250); }); speedButton.addEventListener("click", function () { speed = speed === 1 ? 1.5 : speed === 1.5 ? 2 : 1; speedButton.textContent = speed + "×"; }); document.getElementById("voiceTranscriptToggle").addEventListener("click", function () { var transcript = document.getElementById("voiceTestTranscript"); var open = transcript.classList.toggle("hidden") === false; this.setAttribute("aria-expanded", String(open)); this.textContent = open ? "Hide transcript" : "Read transcript"; }); paintTestimonial();