feat(site): API reference pages for media elements#1342
Conversation
Add generateMediaElementReferences() to the builder entry point so `pnpm api-docs` generates JSON for media elements (hls-video, dash-video, mux-video, mux-audio, native-hls-video, simple-hls-video). Register a new mediaReference content collection in Astro with a Zod schema matching the pipeline output. https://claude.ai/code/session_01GLtyequo6D3zqeddxsBjzQ
Create MediaReference.astro that loads generated media element JSON and renders Host Properties, Native Attributes, Events, CSS Custom Properties, and Slots sections. Add mediaReferenceModel.js for shared heading/id computation. Wire into remarkConditionalHeadings for table-of-contents injection. https://claude.ai/code/session_01GLtyequo6D3zqeddxsBjzQ
Create 7 MDX reference pages: hls-video, dash-video, native-hls-video, simple-hls-video, mux-video, mux-audio (auto-generated via MediaReference), and background-video (hand-authored tables). Add "Media Elements" sidebar section between Components and Hooks & Utilities. https://claude.ai/code/session_01GLtyequo6D3zqeddxsBjzQ
Add BasicUsage demos (HTML + React) for hls-video, dash-video, native-hls-video, simple-hls-video, mux-video, mux-audio, and background-video. Wire demos into each MDX page using FrameworkCase and StyleCase components. https://claude.ai/code/session_01GLtyequo6D3zqeddxsBjzQ
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
✅ Deploy Preview for vjs10-site ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
The React media components (`@videojs/react/media/*`) import from `@videojs/core/dom/media/*` which top-level imports dashjs/hls.js — libraries that access `window` at module load time. This crashes Astro's SSR prerender. Remove all demos until the underlying SSR issue is resolved. https://claude.ai/code/session_01GLtyequo6D3zqeddxsBjzQ
…lan-ClRzU # Conflicts: # .gitignore # site/scripts/api-docs-builder/src/index.ts # site/src/content.config.ts # site/src/utils/remarkConditionalHeadings.js
Add BasicUsage demos (HTML + React) for hls-video, dash-video, native-hls-video, simple-hls-video, mux-video, mux-audio, and background-video. Wire demos into each MDX page. Note: React demos currently break the SSR build due to #1343 (top-level hls.js/dashjs imports access `window`). This branch is parked until that issue is resolved. https://claude.ai/code/session_01GLtyequo6D3zqeddxsBjzQ
The React demos for HLS, DASH, Mux, NativeHLS, and SimpleHLS media elements import from @videojs/react/media/* which chains into top-level hls.js/dashjs imports that access `window` at module evaluation time, breaking Astro's SSR prerender. HTML demos and background-video React demo are unaffected. Refs #1343 https://claude.ai/code/session_01GLtyequo6D3zqeddxsBjzQ
📦 Bundle Size Report🎨 @videojs/html — no changesPresets (7)
Media (10)
Players (5)
Skins (30)
UI Components (38)
Sizes are marginal over the root entry point. ⚛️ @videojs/react — no changesPresets (7)
Media (9)
Skins (27)
UI Components (32)
Sizes are marginal over the root entry point. 🧩 @videojs/core — no changesEntries (14)
🏷️ @videojs/element — no changesEntries (2)
📦 @videojs/store — no changesEntries (3)
🔧 @videojs/utils — no changesEntries (10)
📦 @videojs/spf — no changesEntries (4)
ℹ️ How to interpretAll sizes are standalone totals (minified + brotli).
Run |
|
@cursor review |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 1e05bd7. Configure here.
Move custom properties before regular properties per useSortedProperties rule. Add aspect-ratio: 16/9 to video demos to prevent flat layout before video loads. Mux-audio excluded (audio element). https://claude.ai/code/session_01GLtyequo6D3zqeddxsBjzQ
Switch to the standard BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM playback ID used by all other demos. Update DASH URL per reviewer preference. Add predefined height to mux-audio demos to prevent layout shift. https://claude.ai/code/session_01GLtyequo6D3zqeddxsBjzQ
|
I found two docs-generation issues that look worth fixing before this lands:
I tried to leave these as inline review comments, but GitHub would not anchor them because this file is not currently part of the PR diff. |
Match the convention used in existing HTML demos (e.g. play-button) where each attribute is on its own line for readability. https://claude.ai/code/session_01GLtyequo6D3zqeddxsBjzQ
|
One docs-content suggestion for the media reference pages: the generated Native Attributes and Events chip lists may be less useful than a short explanation of the forwarding behavior. For attributes, the accurate statement is not quite “all native attributes are forwarded,” but rather that these elements accept common native media attributes and forward the supported set from
For events, the runtime behavior is more useful than the exhaustive list: native media events are re-dispatched from the internal media element, so consumers can listen on the custom element directly. Something like: el.addEventListener('play', onPlay);
el.addEventListener('timeupdate', onTimeUpdate);Then list the element-specific events separately, e.g. for HLS/native HLS:
That would probably read better than a large wall of event chips like |
…d events PR #1342 shipped 7 media element reference pages, but the api-docs-builder emitted empty `hostProperties: {}` for any element whose host extends a mixin call expression (mux-video, mux-audio, native-hls-video, simple-hls-video) — `extractClassProperties` only followed `Identifier` extends. Element-specific events (`streamtypechange`, `targetlivewindowchange`) dispatched in mixin code were also missing. This commit: - Generalizes `extractClassProperties` to walk mixin call expressions. Mixins are applied innermost-first so outer overrides win. Supports the three mixin shapes used in the codebase (function declaration, const arrow with named type, const arrow with inline generic) plus parens / as casts and re-exports through barrel files. - Adds dist→source remapping: workspace imports via `package.json#exports` resolve to `dist/dev/*.d.ts` files where TypeScript collapses mixin chains into opaque `_base` aliases. We remap to the corresponding source `.ts` so the chain remains walkable. - Tags host properties whose name matches a member of HTMLMediaElement / HTMLVideoElement / HTMLAudioElement with `overridesNative: true`. The field is omitted (not `false`) when not an override; presentation can decide what to do with it. - Adds description fallback through the chain — child overrides without JSDoc inherit the closest ancestor's description. - Splits `events` into `{ native, elementSpecific }`. Native still comes from the VideoEvents/AudioEvents capability contracts; element-specific is collected by AST-scanning host + mixin files for `this.dispatchEvent(new Event('name'))` and deduping against native. - Adds a `MixinVideo` e2e fixture (function-declaration + const-arrow mixins, native overrides, description fallback, dispatched events) and matching assertions. Existing event assertions updated for the new shape. - Updates the rendered Events section + TOC model to read the new shape.
Audit of the rendered prose against the data surfaced several claims that didn't hold: - Attributes were labeled "native media attributes" but the list includes stream-type (custom) and loading (not a native <video> attribute). Drop the "native" claim; reference MDN for the standard ones. - The "Lower-level options ... Set them in JavaScript" note was both redundant with Host Properties and wrong: most of the props it named are read-only. Removed. - React events claimed every native event maps to a React prop, but addtrack/removetrack/change and the Picture-in-Picture events have none. Split into prop-backed events and ref + addEventListener events, mirroring the element-specific section. - Methods were linked as "HTMLMediaElement methods" but fullscreen and Picture-in-Picture methods live on Element/Document/HTMLVideoElement. Reworded to point at HTMLMediaElement for the core methods. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EQEjBw9Goz81HVbKCk6in3
The comma-separated code chips rendered the separator as a text node on a line of its own (the formatter splits the chip and the separator across lines inside the .map() callback). Astro turned that newline into a space *before* the comma, so the comma could wrap to the start of the next line. Render each chip through a small CodeChip component whose markup stays on one line, and emit the separator as a ::after pseudo-element. The comma is glued to its chip with no preceding text node, and the only break opportunity is the trailing space inside the separator — so a wrap always lands after the comma, never before it. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EQEjBw9Goz81HVbKCk6in3
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EQEjBw9Goz81HVbKCk6in3
The `error` getters described `null` behavior the `| null` type already conveys; drop it. The track/rendition getters led with the property name; lead with the non-obvious availability condition instead. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EQEjBw9Goz81HVbKCk6in3
| for (const candidate of candidates) { | ||
| if (fs.existsSync(candidate)) return candidate; | ||
| } | ||
| return resolvedPath; |
There was a problem hiding this comment.
Dist remap fails Windows paths
Medium Severity
mapDistToSource only matches module paths with forward slashes. On Windows, TypeScript resolution often returns backslash paths, so workspace imports stay on rolled-up dist/dev .d.ts files. Mixin host extraction then reads collapsed declarations instead of source, producing incomplete or wrong media API JSON.
Reviewed by Cursor Bugbot for commit 6c7555a. Configure here.
`error` of type `... | null` is self-documenting; the description only restated the name. The reference table still surfaces "Read-only." for the row, so nothing of value is lost. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EQEjBw9Goz81HVbKCk6in3
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
There are 2 total unresolved issues (including 1 from previous review).
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 1edc544. Configure here.
| const programOptions: ts.CompilerOptions = { | ||
| ...compilerOptions, | ||
| lib: dedupeStrings([...(compilerOptions.lib ?? []), 'lib.dom.d.ts']), | ||
| }; |
There was a problem hiding this comment.
Invalid DOM lib compiler option
Medium Severity
The media reference program adds 'lib.dom.d.ts' to compilerOptions.lib, but TypeScript expects lib entries such as 'DOM', not a declaration filename. With an invalid lib entry, DOM types may not load, so collectNativeMemberNames can fail to resolve HTMLMediaElement members and overridesNative may never be set in generated JSON.
Reviewed by Cursor Bugbot for commit 1edc544. Configure here.
The demo loaded `highest.mp4` (~161 MB) of an asset with no smaller rendition, so the decorative background was slow to start. Point it at a ~29 MB clip instead. (background-video plays through a native <video>, so HLS isn't an option outside Safari.) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EQEjBw9Goz81HVbKCk6in3
The two one-line snippets duplicated the Basic Usage demo right below them. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EQEjBw9Goz81HVbKCk6in3
`height: 100%` doesn't resolve reliably against an `aspect-ratio`-sized parent, so the host could collapse and the absolutely-positioned shadow <video> had nothing to fill. Lay the container out as a single-track grid so the element stretches to fill instead. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EQEjBw9Goz81HVbKCk6in3
The React live demos for engine-backed media elements can't render: the media classes instantiate DOM globals during render, which throws under SSR (#1343). Until that's fixed, render the demo source in tabbed code blocks via <ServerCode> so React readers still get the bare, copyable example. HTML keeps its live <Demo>. Restore <Demo> once #1343 lands. Also converts simple-hls-audio-only, whose live React demo was left active and hit the same SSR break. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EQEjBw9Goz81HVbKCk6in3
luwes
left a comment
There was a problem hiding this comment.
Great start, thank you! There's many native media / video props missing from the base classes, maybe intentional.
|
Hah not intentional. What are you noticing? I'll ship this as is and we'll follow up in a different scope! |
|
https://github.com/videojs/v10/blob/main/packages/core/src/dom/media/media-host.ts#L128-L328 most of these props and methods should be available for media based on the native browser |


Adds API reference pages for the media elements.
What you need to know about api references before reviewing this PR.
This is the api reference generator pipeline
What's new in this PR?
Ok how do I review this?
Changes to input
The output
Review prose, code examples, and whether the generated tables are any good.
Oh, and
background-videois totally hand-authored because it doesn't adhere to the usual media shape.hls-videomux-videomux-audionative-hls-videodash-videosimple-hls-videosimple-hls-audio-onlybackground-videoFuture work
window#1343References
Closes #1253. Closes #1507. Closes #1249.
https://claude.ai/code/session_01EQEjBw9Goz81HVbKCk6in3
Note
Low Risk
Changes are mostly documentation, build-time extraction, and JSDoc; runtime playback logic is largely untouched aside from comments.
Overview
Adds generated API reference for streaming media custom elements (HLS, DASH, Mux, SPF audio-only, etc.) and wires them into the docs site, alongside hand-authored
background-videoreference and HTML/React usage demos.The api-docs-builder gains a
generateMediaElementReferencespipeline that walks host classes through mixin chains and cross-package barrels, maps dist.d.tsback to source for extraction, pulls*DefaultPropsdefaults,@fires/ dispatch for element-specific events,overridesNativevslib.dom, inferred getter types, and per–media-type methods; output shape drops slots and splits events into native vs element-specific. The builder entry point writes validated JSON undergenerated-media-reference/.Site: new
mediaReferenceAstro collection,MediaReference/ host props tables, TOC viamediaReferenceModel+remarkConditionalHeadings, a Media Elements nav section, and MDX pages that embed generated tables (React live demos deferred to source-only tabs pending SSR).Core / SPF: JSDoc on
engine,config, live/stream-type APIs, and@firestags so generated docs carry accurate descriptions.Reviewed by Cursor Bugbot for commit f1e0720. Bugbot is set up for automated code reviews on this repo. Configure here.