Audio Customer Stories
A free audio testimonial section with native playback, selectable customer voices and complete transcripts.
Customise
Code
<AudioCustomerStories
stories={stories}
/>Audio Customer Stories is a free audio testimonial React section for Next.js and React, styled with Tailwind and enhanced with Motion. It presents two to six customer voices as an accessible selector beside a native audio player, a pull quote, a human-readable duration and the complete transcript.
Selecting another story pauses and resets the previous recording without moving focus or starting the new source. The decorative waveform uses deterministic CSS bars and only pulses while native audio is playing on screen, while reduced motion keeps it fully static. Hidden tabs pause playback without resuming it automatically, and every story remains usable through native controls and a standard disclosure.
Install
Add the @te registry to your components.json once:
{
"registries": {
"@te": "https://templateempire.io/r/{name}.json"
}
}Then install the component:
npx shadcn@latest add @te/quote-audio-storiesUsage
import { AudioCustomerStories } from "@/components/quote-audio-stories";
const stories = [
{
id: "nadia-chen",
audioSrc: "/audio/nadia-chen.mp3",
quote: "The page finally sounds like the product feels.",
attribution: "Nadia Chen, Creative Director at Northline",
duration: "0:42",
transcript: "The complete transcript of Nadia's customer story.",
},
{
id: "elias-morgan",
audioSrc: "/audio/elias-morgan.mp3",
quote: "The native player kept the experience familiar.",
attribution: "Elias Morgan, Founder at Sunday Press",
duration: "0:36",
transcript: "The complete transcript of Elias's customer story.",
},
];
export function Example() {
return <AudioCustomerStories stories={stories} />;
}Props
| Prop | Type | Default | Description |
|---|---|---|---|
| stories | ReadonlyArray<{ id; audioSrc; quote; attribution; duration; transcript }> | required | Two to six stories with unique ids, native audio sources, quotations, attributions, display durations and complete transcripts. |
| initialId | string | undefined | Initially selected story id. An invalid id falls back safely to the first story. |
| layout | "rail" | "split" | "split" | Wide-screen composition. Split places the selector beside the player, while rail places the selector above it. |
| barCount | number | 24 | Decorative waveform bar count, clamped to 8 to 48. |
| pulseAmount | number | 0.42 | Maximum scale increase for each active waveform bar, clamped to 0 to 0.8. |
| crossfadeDuration | number | 0.35 | Quote and player transition duration in seconds, clamped to 0 to 0.8. |
| radius | number | 24 | Selector and player corner radius in CSS pixels, clamped to 0 to 44. |
| onStoryChange | (id: string) => void | undefined | Called after a user changes the selected story. |
| className | string | undefined | Additional classes merged onto the section. |
Customisation
Audio Customer Stories exposes four Tier 3 tokens. --audio-stories-accent defaults to var(--primary) for the selected story and active bars, --audio-stories-accent-text defaults to var(--primary-accent) for the transcript summary on hover and focus, --audio-stories-panel defaults to var(--card) for player surfaces, and --audio-stories-wave defaults to var(--muted-foreground) for resting bars. The component also falls back to the library surface and muted tokens when those shadcn tokens are not present. Use the scalar props to tune layout, waveform geometry, transition pace and corner radius:
.audio-stories-theme {
--audio-stories-accent: var(--ring);
--audio-stories-accent-text: var(--primary-accent);
--audio-stories-panel: var(--surface);
--audio-stories-wave: var(--muted);
}
<AudioCustomerStories
stories={stories}
layout="rail"
barCount={36}
pulseAmount={0.28}
crossfadeDuration={0.2}
radius={16}
className="audio-stories-theme"
/>Frequently asked questions
- Is Audio Customer Stories free for commercial use?
- Yes. Audio Customer Stories is MIT licensed, so you can use it in personal and commercial projects without attribution.
- Is this audio testimonial section accessible and performant?
- Yes. Story choices are native buttons in a labelled list, the active choice uses aria-current, playback uses native audio controls, quotations use blockquote and cite, and each complete transcript opens through a standard details disclosure. The decorative waveform is hidden from assistive technology and uses fixed CSS transform animation with no audio analysis, timer or per-frame React state. Reduced motion removes waveform animation and the story crossfade while leaving selection, playback and transcripts available. Without JavaScript, every story remains listed with its own native player and transcript.
- How can I customise the waveform and player?
- Use barCount and pulseAmount to set waveform density and movement, crossfadeDuration to set the story swap pace, radius to shape the cards, and layout to choose a split or rail composition. The playground exposes exactly those effect controls. Retint the selected state, panel and idle bars with the three audio story CSS variables without changing the component source.