👀 Live Preview
Play the audio — active caption text appears when cues change:

The oncuechange handler runs JavaScript when the cuechange event fires on a TextTrack. That happens when the set of active cues changes during <audio> or <video> playback—for example when a WebVTT caption line starts or ends. Use it to build custom caption displays, log subtitle timing, or sync UI with timed text. Attach the handler to textTrack.oncuechange or addEventListener("cuechange", …) on the track from media.textTracks. Set textTrack.mode to "hidden" or "showing" so cues activate.
TextTrack JS.
Cues updated.
Captions file.
Current lines.
Preferred way.
Property API.
oncuechangeThe primary purpose of oncuechange is to run JavaScript when the active cues on a text track change. Cues are timed lines in a WebVTT file (captions, subtitles, or metadata). When playback reaches a cue start or end time, the browser fires cuechange on the TextTrack object.
Use it to build custom caption panels, highlight transcript lines, log subtitle timing, or sync UI with spoken content. The handler attaches to textTrack.oncuechange or textTrack.addEventListener("cuechange", …)—not as a standard inline HTML attribute on <track>.
Tracks default to mode = "disabled". Set "hidden" (process cues without native display) or "showing" (native captions visible) before cuechange will fire.
Attach the handler on the TextTrack from media.textTracks:
<audio id="clip" controls>
<source src="/audio/count.mp3" type="audio/mpeg">
<track kind="captions" src="/audio/count.vtt" srclang="en" label="English">
</audio>
<script>
const audio = document.getElementById("clip");
const track = audio.textTracks[0];
track.mode = "hidden";
track.addEventListener("cuechange", handleCueChange);
function handleCueChange() {
const cues = track.activeCues;
if (!cues || cues.length === 0) return;
console.log(cues[0].text);
}
</script>TextTrack from audio.textTracks or video.textTracks.textTrack.mode to "hidden" or "showing" so cues become active.textTrack.activeCues inside the handler.textTrack.oncuechange = function() { … }.textTrack.addEventListener("cuechange", handler).oncuechange is an event-handler property on TextTrack, not a string attribute on HTML:
track.oncuechange = handleCueChange — Assign a function reference.track.oncuechange = function() { … } — Inline function.track.addEventListener("cuechange", handleCueChange) — Preferred modern form.const track = video.textTracks[0];
track.mode = "showing";
track.oncuechange = function () {
const panel = document.getElementById("caption-panel");
const cues = track.activeCues;
panel.textContent = cues.length ? cues[0].text : "";
};| Event | When it fires | Handler |
|---|---|---|
cuechange | Active cues on a text track change | textTrack.oncuechange |
activeCues | VTTCue objects active now | Read in handler |
mode | "hidden" or "showing" | Required for cues |
| Custom caption UI | Update a div on cuechange | Common pattern |
timeupdate | Fires often on media element | Different event |
| Target | Supported? | Notes |
|---|---|---|
<audio> + <track> | Yes | Handler on audio.textTracks[n] |
<video> + <track> | Yes | Most common for captions |
<track> inline attribute | No | Not a standard HTML attribute—use JavaScript on TextTrack |
TextTrack object | Yes | Where oncuechange / cuechange attach |
oncuechange vs timeupdate vs onloadedmetadata| Handler | When it fires | Typical use |
|---|---|---|
onloadedmetadata | Media metadata loaded (duration, tracks list) | Wire up text tracks once |
timeupdate | Playback time advances (often ~4×/sec) | Progress bar, custom timers |
oncuechange | Active caption cues change | Custom caption display, transcript sync |
addEventListener on TextTrack, the oncuechange property, and cuechange vs timeupdate.
Play the audio — active caption text appears when cues change:
Listen for cue changes on the TextTrack and read active cue text:
<audio id="clip" controls>
<source src="/audio/count.mp3" type="audio/mpeg">
<track kind="captions" src="/audio/count.vtt" srclang="en">
</audio>
<script>
const audio = document.getElementById("clip");
audio.addEventListener("loadedmetadata", () => {
const track = audio.textTracks[0];
track.mode = "hidden";
track.addEventListener("cuechange", () => {
for (const cue of track.activeCues) {
console.log("Active cue:", cue.text);
}
});
});
</script>After metadata loads, set track.mode so cues activate. The browser fires cuechange whenever the active cue set changes during playback.
Assign the handler with the oncuechange property:
const track = audio.textTracks[0];
track.mode = "showing";
track.oncuechange = function () {
console.log("Cue change detected!");
for (let cue of track.activeCues) {
console.log("Active cue:", cue.text);
}
};The property form is equivalent to a single listener. Use mode = "showing" if you want native captions visible alongside your custom logic.
timeupdate fires often; cuechange only when caption lines change:
audio.addEventListener("timeupdate", () => {
// Fires frequently — good for progress bars
});
track.addEventListener("cuechange", () => {
// Fires only when active cues change — good for captions
});Caption timing is handled by the text track engine. Listen for cuechange instead of polling currentTime on every timeupdate.
<track kind="captions"> with WebVTT files so deaf and hard-of-hearing users can follow content.mode="showing" or a custom accessible caption panel should display text visibly.aria-live="polite" for screen reader updates.Link captions file on audio/video.
From media.textTracks.
hidden or showing.
Read activeCues.
The cuechange event and oncuechange handler on TextTrack are supported in all modern browsers — Chrome, Firefox, Safari, and Edge — for WebVTT captions on <audio> and <video>.
oncuechange supportAll major browsers fire the underlying event and honor the oncuechange handler attribute.
Bottom line: Universal support for TextTrack cuechange. Test with real WebVTT files and both audio and video elements.
"hidden" for custom UI or "showing" for native captions.<track>.currentTime to guess caption timing.activeCues may be empty—clear your caption panel.The oncuechange handler runs JavaScript when the cuechange event fires on a TextTrack. Active caption cues change as media plays, so you can build custom caption displays or sync UI with timed text.
Set textTrack.mode, read activeCues in your handler, and prefer addEventListener("cuechange", …) over polling timeupdate.
oncuechangeBookmark these before wiring your next event handler.
Active cues update.
EventJS object API.
ScopeCurrent caption lines.
PatternPreferred.
ModernCues must activate.
Notecuechange event fires on a TextTrack — when active caption or subtitle cues change during media playback.TextTrack from audio.textTracks or video.textTracks — not as a standard inline HTML attribute on <track>.activeCues is a list of VTTCue objects currently active at the media currentTime. Read cue.text in the handler to display caption text.timeupdate fires often as playback time advances. cuechange fires only when the set of active cues changes — when a caption line starts or ends.textTrack.addEventListener("cuechange", …). The oncuechange property works the same way on the TextTrack object.textTrack.mode to "hidden" or "showing". Default mode is "disabled" and cues will not become active.Practice addEventListener cuechange, the oncuechange property, and comparison with timeupdate in the Try It editor.
5 people found this page helpful