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:

📖 Docs:

💻 GitHub:

2 views

Add a comment

Replies

Be the first to comment