mantine-audio 1.1.0 — captions on a player with no picture
Hey everyone 👋
mantine-audio v1.1.0 is out — the Mantine-native audio player with waveform and spectrum visualisers — and it can do captions now.
The part I got wrong in my estimate
I shipped the same feature on the sibling video player the same week and assumed audio would be the identical job with a different tag. It isn't. Adding captions to a video player is one prop: the browser paints the cue text over the picture for you.
An <audio> element has no picture. There is no surface for a browser to paint on, so a caption track can be perfectly attached, perfectly parsed, cues firing on time — and be completely invisible. The text has to be read off the TextTrack API and rendered as ordinary DOM.
So it took three pieces, not one
tracks — the prop, one <track> per entry inside the <audio>
Audio.Captions — renders the active cue, as a polite live region so a screen reader announces each new line. keepSpace and placeholder hold the box in the layout so nothing shifts between lines.
Audio.CaptionsButton — toggles them, and hides itself when there is no caption track
Both sub-components are already in the default control bar, so this is the whole setup:
<Audio
src="/talk.mp3"
tracks={[{ src: '/talk-en.vtt', srcLang: 'en', label: 'English', default: true }]}
/>Building your own UI instead? useAudio returns activeCueText, captionsEnabled, hasCaptions and toggleCaptions.
Two takeaways worth passing on 🙏
First: when you port a feature to a sibling surface, ask what the platform was silently doing for you on the original. The parts a browser handles invisibly are exactly the parts you forget to budget, because you never wrote them the first time.
Second, and more concrete if you build anything media-related: jsdom stubs the TextTrack API. textTracks.length stays 0 even with a <track> sitting in the DOM, addEventListener on the list is undefined. Every caption test written through real markup passes while asserting nothing — and looks thorough doing it. I moved the cue logic into pure functions and verified the rest by driving a real Chrome over the DevTools Protocol.
I'd love your input
For an audio player, would you rather the library render the cue for you, or hand you activeCueText and stay out of the way? Both are in there now and I genuinely don't know which people will reach for.
Anyone doing transcript-style captions (a scrolling full transcript rather than one line at a time)? That is the obvious next step and I'd like to hear how you'd want it shaped.
Drop a comment below — I read every one.
📦 npm: https://www.npmjs.com/package/@gfazioli/mantine-audio


Replies