React Audio Player mit Waveform: Scrubbing und Peaks

Du brauchst einen React Audio Player mit Waveform: eine Podcast-Folge auf einer Landing Page, Sprachnachrichten in einem Chat oder aufgezeichnete Anrufe in einem CRM. Das native Element <audio controls> spielt die Datei ab, sieht aber in jedem Browser anders aus, zeigt keine Waveform und passt schlecht in eine Chat-Blase. Eine Waveform-Library zeichnet die Balken; die schwierigen Teile bleiben trotzdem bei dir: Scrubbing auf dem Smartphone, Spulen per Tastatur, was ein Screenreader hört und der Sprung im Layout, wenn die echte Waveform eintrifft. Dieser Guide behandelt genau diese Teile mit dem Audio Player von Wingo UI und dem Hook useMediaControls, auf dem er aufbaut.
Was muss ein React Waveform Audio Player können?
Sieben Dinge. Ein React Waveform Audio Player, der im Produktiveinsatz besteht, braucht:
- Klicken, Tippen und Ziehen zum Spulen auf den Balken, und die Zeit folgt dem Finger, während du ziehst.
- Spulen per Tastatur mit den Pfeiltasten, Bild auf und Bild ab, Pos1 und Ende.
- Einen Slider, der eine Zeit ansagt. Screenreader lesen die Position als Text vor, etwa „1:12 of 4:05“, statt einer rohen Sekundenzahl.
- Ein stabiles Layout. Die Waveform hat ab dem ersten Render eine feste Höhe und Platzhalter-Balken, damit nichts springt, wenn die dekodierten Peaks eintreffen.
- Peaks, die auch für lange Dateien taugen. Kurze Clips kannst du im Browser dekodieren; lange brauchen vorberechnete Peaks.
- Immer nur einen aktiven Player. Startet eine Sprachnachricht, pausiert die, die gerade lief.
- Geschwindigkeit, Sperrbildschirm und Kopfhörertasten, denn Podcasts hören viele mit 1,5x und dem Handy in der Tasche.
Wie schneiden die Waveform-Optionen im Vergleich ab?
Die eigentliche Wahl: eine Waveform-Library, die du in deine eigene Oberfläche einbaust, oder eine fertige Player-Komponente. Die Tabelle stellt je ein Beispiel gegenüber, mit Fakten aus der öffentlichen Doku der Projekte, Stand Oktober 2026.
wavesurfer.js ist die bessere Wahl, wenn die Waveform selbst das Produkt ist: Bearbeiten, Regionen, Zoomen oder ein Spektrogramm. Für einen Podcast Player in React oder einen Player für Sprachnachrichten ist ein fertiger Player weniger Arbeit: Er hat die Bedienelemente, die Tastaturbelegung und die Lade- und Fehlerzustände schon an Bord.
Welche Props braucht der Audio Player?
Nur src. Alles andere hat einen Default: die Variante card, den neutralen Tone, Skip-Buttons für 15 Sekunden, ein Geschwindigkeitsmenü von 0,5x bis 2x und so viele Balken, wie in die Breite passen.
Am häufigsten änderst du variant (card, compact oder minimal), tone oder color für die gespielten Balken und den Play-Button, skipSeconds (0 blendet die Skip-Buttons aus), rates für die Liste der Geschwindigkeiten sowie barWidth, barGap und waveformHeight für dichtere oder höhere Balken. title, subtitle und cover werden während der Wiedergabe außerdem zu den Metadaten auf dem Sperrbildschirm.
Drück auf Play und zieh dann über die Balken. Mit der Maus siehst du beim Hovern die Zeit über dem Cursor; mit der Tastatur springst du per Tab zur Waveform und nutzt die Pfeiltasten.
$ npx wingo-ui@latest add audio-playerWie vermeide ich Layout-Sprünge, während die Waveform lädt?
Reservier den Platz und füll ihn ab dem ersten Render mit Balken. Die Waveform ist in der Karte 40px hoch und im kompakten Player 28px (waveformHeight überschreibt beides), ihre Box ändert also nie die Größe. Solange es keine echten Peaks gibt, zeichnet der Player placeholderPeaks(src, count): stabile, sprachähnliche Balken, die aus der URL abgeleitet werden und auf Server und Client identisch sind. Es gibt also keinen Hydration-Mismatch. Auf dem Server verteilen sich die Balken über die Breite; nach dem Mount zählt ein ResizeObserver, wie viele Balken von je barWidth + barGap hineinpassen, und zeichnet neu.
Treffen die dekodierten Peaks ein, überblenden die neuen Balken die Platzhalter. Der gespielte Teil besteht aus denselben Balken im Tone, per clip-path aus einem Motion Value zugeschnitten. So löst die Wiedergabe nur einen Repaint aus, statt React bei jedem Frame neu zu rendern. Der Zeittext nutzt Tabellenziffern und wechselt bei Aufnahmen ab einer Stunde in ein Format mit Stunden, damit seine Breite nicht zappelt.
Soll ich Peaks im Browser dekodieren oder vorberechnen?
Kurze Dateien dekodierst du, lange rechnest du vor. Ohne den Prop peaks wartet der Player, bis er höchstens 200px vom Viewport entfernt ist, lädt die Datei, dekodiert sie mit einem OfflineAudioContext und behält pro Abschnitt den lautesten Wert (decodePeaks cacht das Ergebnis pro URL und Balkenzahl). Für eine Sprachnachricht von 30 Sekunden ist das in Ordnung. Die Performance-Hinweise von wavesurfer.js (opens in a new tab) erklären die Grenze: Das Dekodieren mit Web Audio hält die ganze Datei als rohes PCM im Speicher, und ein Stereo-Track von 60 Minuten kann auf über 500 MB kommen. Außerdem muss die Datei für das Dekodieren auf deiner Origin liegen oder mit CORS ausgeliefert werden; eine blockierte Datei bleibt bei den Platzhalter-Balken.
Für Podcasts und Anrufaufzeichnungen erzeugst du die Peaks einmal beim Upload. audiowaveform (opens in a new tab) von der BBC schreibt sie als JSON; dieser Befehl stammt aus dem Peaks-Guide von wavesurfer.js (opens in a new tab):
Das Array data im JSON enthält pro Kanal abwechselnd Minimum und Maximum (Datenformat (opens in a new tab)). Der Player will pro Balken eine Zahl von 0 bis 1, in beliebiger Länge. Fass also jedes Paar zu seinem größeren Absolutwert zusammen, reduzier auf ein paar hundert Abschnitte und normalisier:
Dann liest du die Datei in einer Server Component und gibst sie weiter. Der Player überspringt das Dekodieren und zeigt die echte Waveform schon im Server-HTML:
Wie baue ich einen Player für Sprachnachrichten in React?
Nimm variant="compact": Play, Balken, Zeit und ein Geschwindigkeits-Chip, der bei jedem Tippen zwischen 1x, 1,5x und 2x wechselt, passend für eine Chat-Blase. Leg einen Avatar oder ein Mikrofon-Icon in leading. exclusive ist standardmäßig an, also pausiert eine startende Sprachnachricht jeden anderen exklusiven Player auf der Seite.
Der kompakte Player zeigt vor dem Start die Länge und danach die Position. Die andere Hälfte ist das Aufnehmen: Der Voice Input nimmt mit MediaRecorder auf und gibt dir den Blob, und der Guide zum React Speech to Text Input behandelt Mikrofon, Live-Transkript und Fallback auf den Server.
Eine Falle bei frischen Aufnahmen: Der MediaRecorder von Chrome schreibt WebM-Dateien seit Langem ohne Dauer (Chromium Issue 642012 (opens in a new tab)), deshalb kann das audio-Element Infinity melden. Seit Chrome 140 hat eine Aufnahme am Stück die Dauer, eine mit timeslice oder requestData()-Aufrufen aber weiterhin nicht (Addpipe, aktualisiert im Juni 2026 (opens in a new tab)). Der Voice Input nimmt in Abschnitten von einer Sekunde auf, rechne bei seinen Blobs also mit der fehlenden Dauer. Der Audio Player behandelt eine unendliche Dauer als Livestream: Er zeigt ein Badge „Live“ und schaltet das Spulen ab. Korrigier die Dauer in der aufgenommenen Datei, bevor du sie abspielst, oder spiel die hochgeladene Datei ab, sobald der Server sie gespeichert hat.
Wie zeige ich aufgezeichnete Anrufe in einer Liste?
Nimm variant="minimal": Play, eine dünne Leiste zum Scrubben, die Zeit und optional einen Download-Button, klein genug für eine Tabellenzeile oder einen Activity Feed. Die Waveform fällt hier absichtlich weg, denn dreißig Zeilen voller Balken sind nur Rauschen. downloadable ergänzt den Download-Button, und fileName benennt die gespeicherte Datei.
$ npx wingo-ui@latest add audio-playerDas React CRM Template ist ein kompletter Screen, in den solche Anrufzeilen gehören.
Wie mache ich eine Audio-Waveform barrierefrei?
Behandle die Waveform als Seek-Slider. Der Player rendert sie mit role="slider", dem Label „Seek“, aria-valuemin und aria-valuemax in Sekunden und aria-valuetext wie „1:12 of 4:05“. Das ist dieselbe Idee wie im Beispiel für einen Media Seek Slider (opens in a new tab) des W3C, das Sekunden in Minuten und Sekunden umrechnet, damit niemand eine rohe Zahl hört.
Auf der Waveform spulen die Pfeiltasten links und rechts (oder hoch und runter) 5 Sekunden, Bild auf und Bild ab 30, Pos1 und Ende springen zum Anfang oder Ende, und Leertaste, k oder Enter starten und pausieren. Überall im Player spulen j und l 10 Sekunden, m schaltet stumm, 0 bis 9 springen auf 0% bis 90%, und die spitzen Klammern ändern die Geschwindigkeit. Jeder Button behält am Smartphone ein Touch Target von 44px, der Lautstärke-Slider verschwindet auf Touchscreens, wo die Hardwaretasten das übernehmen, und das Geschwindigkeitsmenü öffnet sich unter 768px als Bottom Sheet. Eine fehlende Datei zeigt eine Meldung mit „Erneut versuchen“ statt eines Buttons, der nichts tut. Alle Texte liegen in labels und werden über DEFAULT_AUDIO_PLAYER_LABELS gemergt.
Wie baue ich ein eigenes Layout mit useMediaControls?
Kombinier den Hook mit dem exportierten Part Waveform. So wird daraus eine React Waveform Komponente, die du in jedes Layout setzen kannst. useMediaControls gibt dir einen ref für das <audio>-Element, State wie playing, duration und second (ganze Sekunden, höchstens ein Render pro Sekunde), Motion Values für progress und buffered sowie Aktionen wie toggle, seek, seekBy, seekToFraction und setRate. handleMediaKey gibt jedem Root-Element dieselbe Tastaturbelegung.
aria-label und aria-valuetext gibst du hier selbst mit: Mit einem Motion Value für progress kann Waveform keinen Zahlenwert berechnen. Musst du nur auf die Wiedergabe reagieren, hat AudioPlayer den Prop setApi, der dir dieselben Steuerungen ohne ref gibt, etwa um den aktuellen Satz eines Transkripts hervorzuheben und zu spulen, wenn jemand auf eine Zeile tippt.
$ npx wingo-ui@latest add use-media-controlsWas sind die typischen Fallstricke?
- Eine von CORS blockierte Datei. Zum Dekodieren muss
fetchdie Bytes lesen. Dateien auf einer anderen Domain ohne CORS-Header spielen problemlos ab, behalten aber die Platzhalter-Balken. Übergibpeaksoder liefere die Datei mit CORS aus. - Lange Aufnahmen dekodieren. Rechne Peaks für alles vor, was länger als ein paar Minuten ist, sonst zahlt der Tab für das ganze PCM im Speicher.
preload="none"ohne Dauer. Der Player zeigt--:--bis zum ersten Abspielen. Bleib beimetadata, außer du renderst Hunderte Zeilen.- Zwei Player, die gleichzeitig reden. Lass
exclusivein Chat-Verläufen und Folgenlisten an. - Frische WebM-Blobs in Chrome. Aufnahmen in Abschnitten haben weiterhin keine Dauer. Korrigier sie oder spiel die hochgeladene Datei ab, wie oben beschrieben.
Wie füge ich ihn meinem Projekt hinzu?
Führ npx wingo-ui@latest add audio-player aus. Die CLI kopiert audio-player.tsx nach components/ui und use-media-controls.ts nach hooks, ergänzt die Items, auf denen der Player aufbaut (Button, Dropdown Menu, Popover, Slider, Spinner, Tooltip und ein paar Helfer), und installiert die npm-Pakete, die sie brauchen, etwa motion und lucide-react. Der Audio Player, der Hook und der Voice Input sind Pro-Items: Pro kostet 8 $ im Monat, 80 $ im Jahr oder einmalig 150 $, Stand Oktober 2026 (Preise). Weitere Deep Dives zu einzelnen Komponenten findest du in der Kategorie Komponenten-Guides, und der Guide zu React Form Components wendet dieselben Regeln für Tastatur, Touch und Screenreader auf jedes Formularelement an.
Häufige Fragen
Wie zeige ich in React eine Waveform für eine Audiodatei an?
Entweder dekodierst du die Datei im Browser mit der Web Audio API und nimmst pro Abschnitt den lautesten Wert, oder du berechnest die Peaks auf dem Server vor, etwa mit audiowaveform von der BBC, und übergibst sie als Array. Für kurze Sprachnachrichten reicht das Dekodieren im Browser; für Podcasts und lange Anrufe rechnest du vor.
Ist wavesurfer.js der beste Weg zu einer Waveform in React?
wavesurfer.js ist eine ausgereifte Library unter BSD-3-Clause mit einem offiziellen React-Paket, @wavesurfer/react, das eine Komponente WavesurferPlayer und einen Hook useWavesurfer exportiert. Die Library passt gut, wenn du Regionen, Spektrogramme oder andere Plugins brauchst. Willst du eine fertige Player-Oberfläche mit Layouts für Chat und Anruflisten als Quellcode, den du ändern kannst, passt eine Komponente wie der Audio Player von Wingo UI besser.
Wie mache ich eine Audio-Waveform per Tastatur bedienbar?
Gib der Waveform role slider, ein Label wie Seek und aria-valuetext mit der Position als Text, zum Beispiel 1:12 of 4:05, damit ein Screenreader keine rohe Sekundenzahl vorliest. Die Pfeiltasten sollten ein kleines Stück springen, Bild auf und Bild ab ein größeres, wie im Beispiel für einen Media Seek Slider des W3C.
Warum hat meine aufgenommene WebM-Sprachnachricht in Chrome keine Dauer?
Der MediaRecorder von Chrome schreibt WebM-Dateien seit Langem ohne Angabe der Dauer (Chromium Issue 642012), deshalb kann das audio-Element Infinity melden. Chrome 140 trägt die Dauer bei Aufnahmen am Stück ein, Aufnahmen mit timeslice oder requestData() haben sie aber weiterhin nicht. Korrigier also die Dauer in der Datei oder spiel den gespeicherten Upload statt des frischen Blobs ab.
Ist der Audio Player von Wingo UI kostenlos?
Nein. Der Audio Player, der Hook useMediaControls und der Voice Input sind Pro-Items. Einige Bausteine, auf denen sie aufbauen, etwa Button, Tooltip, Popover, Dropdown Menu und Spinner, sind kostenlos; der Slider ist Pro.
- Audio
- Waveform
- Sprachnachrichten
- Barrierefreiheit
- React


