Skip to content
Breaking changes

v10.0.0-rc.5

Compare changes on GitHub

This is the last round of API cleanup before 10.0: the Minimal skin becomes Neutral, the player store adopts media element names, and a new Compat skin joins wider browser support.

Breaking changes

If you use the Default skin with no custom UI and no hand-wired extensions, there’s nothing to change. Otherwise, start with the first two.

Likely to affect you

  • Minimal is now Neutral (#3092). This affects anyone on the Minimal skin, however you installed it. Rename every minimal to neutral: import paths, Minimal*Skin components, <*-minimal-skin> elements, data-theme, family="minimal" icons, CDN *-minimal.* files, Shadcn r/*/minimal paths, and --skin minimal. There are no aliases. Old import paths fail at build time, but some failures are quiet: an old CDN URL returns 404, and CSS that targets data-theme="minimal" stops matching. See Customize skins.

  • The player store uses media element names (#3012). This affects custom UI that reads state or calls actions on the store. Toggles split into explicit pairs, and state fields take the HTMLMediaElement names. TypeScript flags each rename. In plain JavaScript, an old field reads as undefined without an error, and an old action throws when called.

    Before After
    togglePaused() play() or pause()
    toggleMuted() setMuted(muted)
    toggleFullscreen() requestFullscreen() or exitFullscreen()
    togglePictureInPicture() requestPictureInPicture() or exitPictureInPicture()
    toggleRemotePlayback() promptRemotePlayback()
    fullscreen isFullscreen
    pip, pipAvailability isPictureInPicture, pictureInPictureAvailability
    source (string or null) currentSrc (always a string)
    loadSource(src) Set src or source on the media element

    toggleSubtitles() and toggleControls() stay, and hotkey and gesture action names such as togglePaused are unchanged. canPlay now turns true at HAVE_FUTURE_DATA, and requestPictureInPicture() rejects before metadata loads. See the player store reference.

Only if you use these APIs

  • Thumbnail and subtitle state (#3057). Custom thumbnail or captions UI: read thumbnailsTrack ({ cues, src, crossOrigin } or null) instead of thumbnailCues, thumbnailTrackSrc, and thumbnailTrackCrossOrigin. Call selectSubtitlesTrack(null) instead of passing 'off'.
  • Hand-wired extensions (#2880). Mounted <google-cast>, <mux-data>, <GoogleCast>, and <MuxData> need no change. If you called useMediaExtension, addMediaExtension, or an extension’s setAdapter(), render the element or component inside the player instead.
  • Tailwind skin source (#3094). If you added skin source to your project, rename the media-opaque variant to media-high-contrast. Its behavior is unchanged.
  • Exhaustive IndicatorStatus switches (#3064). IndicatorStatus now accepts custom strings, so a switch that covers every status needs a default case. Use BuiltInIndicatorStatus for the built-in names only.

Skins and browser support

The new Compat skin offers a simpler control layout with conservative CSS for video, live video, audio, and live audio. It ships in the HTML and React packages, CDN bundles, Shadcn registries, and installation tools (#3026).

Packaged skins now support Chrome and Edge 111, Firefox 121, and Safari and iOS 16.4. Their bundles flatten @scope rules and include CSS fallbacks, while editable registry CSS keeps @scope for readability (#2966, #2951). See browser support for details.

We also restored the closing transition on nested menus and lowered the default skin’s backdrop saturation so controls read more clearly (#3025, #3091).

Media and playback

resolveAdapterType() and resolveMimeType() pick the right media component from a URL or MIME type, using the same rules as the installation flow. They handle service URLs, streams, and files, recognize youtube/<id> and vimeo/<id> shorthands, and return null for ambiguous bare IDs (#3024).

Google Cast and Mux Data now attach at the player, so they work with a plain <video> or <audio> and follow media changes. A refused play or AirPlay request no longer surfaces as an unhandled rejection (#2880). Native HLS honors a stream’s SERVER-CONTROL hold-back when it finds the live edge, and hls.js keeps captions when media attaches after the manifest loads (#3027, #3099).

React and custom UI

  • React Server Components can now call @videojs/react helpers such as mergeProps and read its constants. Each component and hook module declares its own client boundary, instead of the package barrels marking every export as client-only (#3079).
  • React media components accept mediaRef. On native media it receives the element; on iframe embeds such as YouTube and Vimeo it receives the playback adapter, so you can call play() without useMedia(). ref still points to the rendered element (#3098).
  • The status indicator can show feedback for your own hotkey actions through deriveCustomStatus (#3064).
  • Core, HTML, and React each export a VERSION constant for diagnostics (#3078).

Documentation

The new Vidstack migration guide maps providers to Video.js media components (#3021). The player store reference lists every state field and action, generated from source, and the migration and playback guides now use current APIs with complete examples and agent-ready migration prompts (#3034, #3074, #3075, #3076).