feat(packages): add text track utilities - #2439
Closed
mihar-22 wants to merge 3 commits into
Closed
Conversation
✅ Deploy Preview for vjs10-site ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
@videojs/core
@videojs/element
@videojs/html
@videojs/media
@videojs/react
@videojs/spf
@videojs/store
@videojs/utils
commit: |
Contributor
📦 Bundle Size Report🎨 @videojs/html
Small changes (62, ≤ 300 B)
Presets (7)
Media (18)
Extensions (2)
Players (5)
Skins (29)
UI Components (50)
⚛️ @videojs/react — 68 small size changes
Presets (7)
Media (22)
Extensions (2)
Players (5)
Skins (26)
UI Components (39)
🧩 @videojs/core — 2 small size changes
Entries (76)
🏷️ @videojs/element — no changesEntries (2)
📦 @videojs/store — no changesEntries (3)
🔧 @videojs/utils — 1 small size change
Entries (13)
📦 @videojs/media
Small changes (11, ≤ 300 B)
Entries (23)
📦 @videojs/spf — 5 small size changes
Entries (10)
ℹ️ How to interpretEach entry is independently bundled, minified, and brotli-compressed. Initial size includes its static import graph; lazy dynamic chunks are reported separately. Entries are not additive because their dependency graphs overlap. Preset rows represent realistic combined bundles. Changes of 300 B or less across initial, lazy, and total size are collapsed, not discarded. Run |
Rename the React creation hook to useCreateTextTrack, notify cue observers when cues are written through a track handle, and defer those writes until the backing <track> element settles because browsers discard cues added before its load completes. Key useActiveTextTrack subscriptions by kind so inline arrays do not resubscribe, and add a browser e2e for src-less programmatic tracks.
mihar-22
force-pushed
the
t3code/add-text-track-hooks
branch
from
September 2, 2026 21:06
cbd5b1c to
ec2a435
Compare
This was referenced Sep 3, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Native media uses real
<track>children for programmatic tracks, which makes cleanup possible. Non-native media can implement the optionalremoveTextTrack()capability. Active-track selection prefersshowing, falls back tohidden, and ignoresdisabled; this keeps chapter and metadata tracks active without rendering them.API surface
React (
@videojs/react)useCreateTextTrack(options)CreatedTextTrack | null{ track, addCue, removeCue }; write cues through those so observers refresh and writes wait for the native<track>to load.useActiveTextTrack(kind)TextTrackLike | nulluseTextCues(track)TextCueLike[]useActiveTextCues(track)TextCueLike[]useCreateTextTrackaccepts:HTML (
@videojs/html)TextTrackControllerhas two source modes:The options overload owns a created track. The kind overload observes an existing active track. Both expose:
.value.cues.activeCues.addCue(cue).removeCue(cue)The controller follows the media context, reconnects when the player changes media, and owns all subscriptions and cleanup.
Shared DOM primitives (
@videojs/media/dom)createTextTrack()returns a{ track, addCue, removeCue, destroy }handle whose cue writes notify observers and wait for the backing<track>to loadaddTextTrackCue()andremoveTextTrackCue()write cues on any track and notify observerscreateTextTrackElement()creates the removable native backing elementgetActiveTextTrack()andwatchActiveTextTrack()select and observe enabled tracksgetTextTrackCues()andwatchTextTrackCues()read and observe cue snapshotsCreateTextTrackOptions,TextTrackHandle, andTextTrackKindFilterdescribe the shared contractsThe framework-neutral media contracts now model optional
activeCues,removeCue(), andremoveTextTrack()support.findTrackElement()also searches a host's open shadow root so wrapped native media can resolve their<track>elements.Usage
Create a programmatic track in React:
Observe a track and its current cues:
Use the HTML controller inside a reactive custom element:
URL-backed WebVTT remains native in both frameworks:
There is intentionally no uppercase
<Track>component: native<track>already composes with every native-backed Video.js media component and retains browser loading, default selection, and fallback semantics. The implementation also keeps the React stores specialized and private rather than exporting a genericcreateExternalStore, and it does not add a runtime kind parser for a TypeScript-only API.Documentation
useCreateTextTrack,useActiveTextTrack,useTextCues,useActiveTextCues, andTextTrackControllerTesting
pnpm -F @videojs/utils test(483 tests)pnpm -F @videojs/media testpnpm -F @videojs/html test(423 tests)pnpm -F @videojs/react test(512 tests)pnpm -F site test scripts/api-docs-builder/src/tests/e2e.test.ts(162 tests)pnpm -F site api-docspnpm -F site astro check(0 errors; existing repository hints only)pnpm typecheckpnpm lintpnpm check:workspaceReview follow-up
useTextTracktouseCreateTextTrack; it creates and owns a track, so the accessor-style name read wrong besideuseActiveTextTrack.TextTrack.addCue()fires no event, souseTextCuesnever saw programmatic cues. Cue writes now go through the track handle (addCue/removeCue) and notify everywatchTextTrackCuesobserver.<track>element's load settles (Chromium wipes them on bothloadanderror). The handle queues writes until the element reports either event, and applies a requesteddisabledmode only after that.useActiveTextTrackkeys its subscription by the joined kinds, so an inline kind array no longer resubscribes every render.apps/e2e/tests/text-track-cues.spec.ts, which verifies in a real browser that a cue on a src-less programmatic track firescuechangeand thatdestroy()removes the element. Passes in Chromium and Firefox with tracing off; locally,trace: 'on'fails on any page that streams remote video, which is unrelated to this spec.main.