Why this matters
If your product ships an HTML5 video player to a browser — a marketing landing page, an OTT catalogue, a podcast site, a course platform, a smart-TV app, a video review tool — the choice of player library decides three things you live with for years: the kilobytes you make every viewer download before the first frame paints, the size of the engineering team you need to maintain it, and the speed at which you can ship new features the design team asks for. Until March 2026 those three numbers were stuck at uncomfortable values for the Video.js half of the market: large bundles, a mid-2010s API, a default skin that nobody wanted to keep. Version ten changes all three at once, and SPF changes a fourth — how much your streaming engine costs in bytes. Whether you are a product manager weighing "do we migrate now or wait for general availability", a frontend engineer evaluating Video.js v10 against React-native alternatives like Vidstack or Media Chrome, or a streaming engineer figuring out whether SPF can replace hls.js on the players you currently ship, this article gives you the structural picture, the numbers, and the call-it-now framework you can take to a planning meeting. No prior streaming knowledge is required; every term is defined where it first appears.
What Video.js v10 is, in one paragraph
Video.js v10 is a complete rewrite of the open-source media player library that has shipped under the video.js name since 2010, redesigned as a modular framework rather than a monolithic player object. The legacy player — every version from 1.x through 8.x — was built around a single videojs(element) constructor that returned a "Player" object containing every feature the library knew about, from the play button through the captions menu to the adaptive-bitrate streaming engine. In version ten the player is instead composed from three independent pieces: a state store (built on the Zustand store-slices pattern), a media component (the actual element or one of its specialised siblings like a YouTube-source component or a background-video component), and a UI built from unstyled primitives in the style of Radix and Base UI (Video.js Project, Video.js v10 Beta: Hello, World (again), 10 March 2026). You instantiate a player by calling createPlayer({ features: [...] }) and you only include the features your application actually uses — if you do not import the audio feature, the bundle does not contain the volume or mute code. The default video bundle is eighty-eight percent smaller in gzip terms than the version-eight equivalent (twenty-five kilobytes against seventy-five). The beta released on 10 March 2026 and the team is targeting general availability in mid-2026, with feature parity with the legacy Plyr, Vidstack, Media Chrome, and Video.js v8 codebases as the GA gate.
That paragraph is the whole product surface. The rest of this article zooms into each piece, names the configuration that matters, and tells you which switches change behaviour in production.
Why this rewrite happened at all
Video.js was built sixteen years ago to help the web cross from Adobe Flash to the new HTML5 element, a job it did so well that by the late 2010s it was the default open-source player on a sizeable share of the web — Brightcove's main product embeds it, every cable-MSO trial of OTT used it as a starting point, and a long tail of small video sites adopted it because there was nothing else mature enough to ship. The price the codebase paid for that early adoption is that its public API reflects 2010-era JavaScript: a global videojs() constructor, prototype-based inheritance for every component, jQuery-style DOM helpers, and a "fork the player and override a method" extension model that did not survive the rise of bundlers, tree-shaking, and React-native composition (Heffernan, S., Video.js v10 Beta: Hello, World (again), 10 March 2026). The third-party plugin ecosystem reinforced the pattern — once thousands of plugins assumed they could extend the Player prototype, the team could not refactor without breaking everyone.
The technical fallout was a default bundle that grew, never shrank. Even after the team did the work to split adaptive-bitrate streaming into the optional videojs-http-streaming plugin in 2018 and let teams import video.js/core to drop it, most installs continued to ship the full bundle — partly out of habit, partly because the default tag setup pulled the full file. By the mid-2020s a default v8 player with adaptive bitrate weighed roughly seven hundred kilobytes minified and just over two hundred kilobytes gzipped, against an HTML5 element that costs nothing. That was the gap version ten was built to close.
The political background matters too. Three other open-source players grew up in parallel to Video.js — Sam Potts' Plyr, focused on visual design; Vidstack, building React-first primitives; and Mux's Media Chrome, focused on HTML web components. By 2025 the four projects shared a maintainer overlap (Mux employs several of the maintainers across the four codebases), a sponsor overlap (Mux sponsors Video.js and built Media Chrome internally), and a common reader frustration: the same engineering choices were being relitigated four times with slightly different APIs. The v10 rewrite consolidated them. The combined collaboration brings, on the project's own count, seventy-five thousand GitHub stars and tens of billions of video plays a month under one roof (Video.js Project, Video.js v10 Beta, 10 March 2026). The four legacy projects continue to ship — Plyr 4, Vidstack stable, Media Chrome — but their next chapter lives inside the videojs/v10 repository.
The new architecture in plain English
A running Video.js v10 player is a small graph of three independent pieces glued together by a Player.Provider context — the new public face of the library that replaces the legacy Player object. The pieces are named State, Media, and UI, and the reason they live in separate files is that they can be used separately.
State is a small reactive store, built on the Zustand store-slices pattern, that holds everything the rest of the player needs to react to: whether the media is paused, where the playhead is, what the buffered range is, whether captions are on, what the volume is, what the current ABR variant is. You add capabilities to the store by passing a features array to createPlayer() — for example, features: [features.playback] ships only the play / pause slice, features: videoFeatures ships the full video slice (audio, captions, time, ABR signals, error handling), and features: backgroundVideoFeatures ships a minimal autoplay-loop slice with no audio code at all (Video.js Project, Concepts: Overview, accessed 2026-05-25). If a feature is not in the array, its code does not enter the bundle — this is the structural reason the React "hello world" example in the announcement post weighs under five kilobytes gzipped.
Media is the component that actually renders the bytes. It can be a plain that wraps the browser's HTML5 element, an for audio-only, a for muted-autoplay landing-page videos, or a format-specific component (HLS, DASH) or service-specific component (YouTube, Vimeo, Mux) that the team plans to ship in the same architecture (Video.js Project, Concepts: Overview, accessed 2026-05-25). The media component exposes a consistent API to the state store regardless of which underlying source it wraps — the rest of the player does not need to know whether it is talking to native HLS, to an HLS.js instance, or to an SPF-composed engine.
UI is a set of unstyled primitives that output a single HTML element each and expose every visual property as a real CSS class you control. The legacy v8 timeline thumb was a pseudo-element on a nested child that you styled by overriding font-size for dimensions. The v10 timeline thumb is and you set width: 0.75rem; height: 0.75rem; directly. The pattern is borrowed from shadcn/ui and Radix — the UI primitives are intentionally verbose because the verbosity is what gives you full control over the markup and the CSS without the player fighting you (Video.js Project, Video.js v10 Beta, 10 March 2026).
A preset is a pre-composed combination of the three. The beta ships three presets — videoFeatures for general website video, audioFeatures for podcast-style audio, and backgroundVideoFeatures for a muted hero-video on a landing page — and the project plans to add more as feedback comes in. You pick the preset closest to the player you want, drop it in, and customise from there.
The composition pattern means a v10 player can sit anywhere on a spectrum from "five-kilobyte hello world" to "full-featured streaming player with ABR, DRM, ads, and analytics". The five-kilobyte case is the React snippet from the announcement post:
import { createPlayer, features } from '@videojs/react';
import { Video } from '@videojs/react/video';
const Player = createPlayer({ features: [features.playback] });
function App() {
const store = Player.usePlayer();
const paused = Player.usePlayer((s) => s.paused);
return (
<Player.Provider>
<Player.Container>
<Video src="video.mp4" />
<button onClick={() => (paused ? store.play() : store.pause())}>
{paused ? 'Play' : 'Pause'}
</button>
</Player.Container>
</Player.Provider>
);
}
The full-featured case is the same createPlayer call with the full feature set, a streaming engine attached, and an ABR-capable media component.
The Streaming Processor Framework, explained
The Streaming Processor Framework — SPF for short — is a separate sister project to Video.js v10 that does for the streaming engine what v10 does for the player: replace a monolithic library with a set of small composable pieces you assemble into the engine your project actually needs. A streaming engine is the part of a web player that does the work the browser will not do natively for adaptive-bitrate formats — parsing the manifest (the small text index file that lists the available video chunks), fetching the segments (the short two-to-six-second video files the manifest points to), feeding those segments into the browser's Media Source Extensions API for decoding, detecting codecs and dropping unsupported renditions, managing the buffer, running the ABR algorithm that picks which quality to fetch next, negotiating decryption keys for DRM-protected content, and inserting server-side ad slates. In hls.js, Shaka Player, dash.js, and the legacy Video.js VHS plugin, that whole stack ships as one library — you cannot trim it without forking the code.
SPF flips the model. The engine is a registry of functional components, and you compose the engine you ship by listing the components you need. An app that streams short-form CMAF-only video with no DRM and no ads composes an engine that contains the CMAF parser, the segment loader, the simple ABR rule, and the MSE source-buffer adapter — and nothing else. An app that streams paid OTT with multi-DRM adds the Widevine, PlayReady, and FairPlay components. An app that runs server-side ad insertion adds the SSAI marker parser. The same engine source tree is the starting point in every case; the difference is what the project's import statements pull in (Video.js Project, Video.js v10 Beta, 10 March 2026).
The numbers in the announcement post are the proof point. A SPF-composed engine for the "simple HLS" case — CMAF-only, on-demand, no ads, no DRM — gzips to twelve and a half kilobytes (Video.js Project, Video.js v10 Beta, 10 March 2026). The comparable hls.js-light build, which is the minimum you can ship of hls.js after removing DRM, subtitles, alt-audio, CMCD, and interstitials, gzips to one hundred and three kilobytes. Full hls.js is one hundred and fifty-six kilobytes; Shaka is two hundred and thirty-nine kilobytes; dash.js is two hundred and ninety-four kilobytes. Walking through the math out loud — twelve and a half divided by one hundred and fifty-six is just under eight percent, which is to say the SPF-composed engine for the simple-HLS case is roughly an eighth of the size of the standard hls.js build. Against hls.js-light specifically the ratio is twelve percent.
There are two caveats the announcement post is careful to spell out, and the article repeats them because they decide whether SPF is the right tool for a given project today. First, SPF is not a drop-in replacement for hls.js, Shaka, or dash.js on advanced workloads. The beta SPF composition covers simple ABR over CMAF; it does not yet cover DRM, ads, or low-latency live. The team's own framing — "the immediate goal isn't for SPF to replace the full-featured engines like HLS.js for advanced streaming use cases" — is the line your engineering team should read aloud before committing to SPF on a DRM-protected production stream. Second, v10 works with the established engines unchanged. You can ship v10 with hls.js, Shaka, or dash.js as the streaming engine today (the announcement post benchmarks the v10 + hls.js combination at one hundred and sixty-four kilobytes gzipped, twenty percent smaller than v8 + VHS at two hundred and three kilobytes for the same workload). SPF is the option you reach for when the use case is simple enough that the savings are worth the trade-off in maturity.
How v10 compares with the previous version and with the other web players
A streaming engineering team picks a player on roughly six axes: default bundle size, ABR-included bundle size, framework story, customisation story, ecosystem maturity, and roadmap visibility. The table below collapses the announcement-post numbers and the public roadmap signals into a single side-by-side view as of May 2026.
| Axis | Video.js v8 (legacy) | Video.js v10 beta | hls.js (light / full) | Shaka Player | dash.js |
|---|---|---|---|---|---|
| Default bundle, no ABR (gzip) | 75.2 kB | 25.1 kB | n/a (engine only) | n/a (engine only) | n/a (engine only) |
| With ABR, "simple HLS" (gzip) | 202.7 kB | 38.7 kB (v10 + SPF) | 103.4 / 155.9 kB | 239.1 kB | n/a (DASH only) |
| With ABR, advanced HLS (gzip) | 202.7 kB | 164.1 kB (v10 + hls.js) | 155.9 kB | 239.1 kB | n/a |
| Framework first-class? | No (legacy globals) | React + TypeScript + Tailwind first-class | No | No | No |
| Customisation model | Prototype overrides | Unstyled primitives + presets | Configuration object | Configuration object | Rules + Settings |
| Format coverage | HLS + DASH + native | HLS + DASH + native (via SPF or external engine) | HLS only | HLS + DASH + Smooth | DASH + Smooth |
| Production maturity | High (ships everywhere) | Beta as of 10 Mar 2026 | High | High | High |
| Best fit in 2026 | Existing v8 deployments | Greenfield projects, simple ABR, React stacks | Advanced HLS | Multi-format OTT with DRM | DASH-reference workloads |
The cell that should slow you down is production maturity: beta as of 10 March 2026. The team is targeting general availability in mid-2026 and has said the API is not yet stable. The right read of that signal depends on whether the project is greenfield or migrating an existing v8 deployment — the next section walks the decision out loud.
A worked migration math example
A non-technical reader needs to see the bundle-size argument with the numbers plugged in, because the rest of the article rests on it. Take a marketing landing page that ships an HLS-encoded product video — a single rendition, no ads, no DRM, captions on, autoplay on muted scroll. Today the page ships Video.js v8 with VHS bundled by default: two hundred and two and seven-tenths kilobytes gzipped, which at a typical mobile-3G download speed of two hundred kilobytes per second works out to roughly one second of pure download time before the player code even begins to execute. The arithmetic out loud:
v8 + VHS gzipped bundle: 202.7 kB
3G download speed: 200 kB/s
Download time: 202.7 / 200 ≈ 1.01 s
Now the same page on Video.js v10 with SPF for the simple-CMAF case: thirty-eight and seven-tenths kilobytes gzipped.
v10 + SPF gzipped bundle: 38.7 kB
3G download speed: 200 kB/s
Download time: 38.7 / 200 ≈ 0.19 s
The page saves roughly eight hundred and twenty milliseconds of network time on every cold-cache load. On a marketing page, where bounce rate climbs nine percent for every additional second of load time (Akamai, State of Online Retail Performance, historical data — cited as illustrative), that is the kind of number that pays for the migration on its own. The picture is less dramatic for an OTT app behind authentication where the player loads once and the user watches for hours — but it is still real, and it compounds across every device profile.
The AI angle
Steve Heffernan's announcement post calls out an angle the rest of the player ecosystem has not addressed head-on: the team designed the v10 codebase for AI-agent comprehension, not just human comprehension. The reasoning is that as more frontend code is written with AI assistance, the player library that an agent can navigate without choking on its own documentation budget is the player library that gets shipped. Three concrete v10 affordances support that goal (Video.js Project, Video.js v10 Beta, 10 March 2026):
A top-level llms.txt file that gives any AI agent a curated, low-context map of the documentation site — pointing the agent at the right pages without loading the full navigation tree. A separate framework-specific llms.txt for the React docs. Markdown versions of every individual documentation page, served by content negotiation: if an agent hits the site with the Accept: text/markdown header, the server returns the markdown source instead of the rendered HTML, saving the agent the cost of parsing a styled page to extract the prose. And a growing set of agent-targeted skills committed under .claude/ and .zed/ directories in the repository (visible in the v10 repo file listing), which the team is using internally and intends to publish for external agent use.
The angle is worth flagging because no other web player library has shipped equivalent affordances in 2026. If your engineering organisation is leaning on AI agents for UI work — and the Fora Soft observation across the e-learning, OTT, and surveillance projects we have shipped in the last year is that the lean is steepening — the v10 codebase is the one your agents will produce correct code against fastest.
A common mistake: equating v10 with SPF
The most common confusion in the early-2026 commentary is that Video.js v10 and SPF are the same thing. They are not. Video.js v10 is the player; SPF is the streaming engine. You can ship v10 with hls.js, Shaka, dash.js, or the legacy VHS, and you can ship SPF as the streaming engine inside other players or even as a standalone — the two projects share a maintainer cohort but live in separate code branches with separate release cadences. The reason to separate them in your head is that the maturity gradients are different: v10 the player is approaching general availability for the kinds of features the legacy v8 covered, while SPF the engine is explicitly scoped at beta to "simple ABR" workloads, with DRM, ads, and low-latency live still on the roadmap. A team can ship v10 + hls.js to production today and pick up SPF later when its feature surface catches up to the project's needs. A team that mistakes the two will either over-promise SPF's coverage or under-rate v10's readiness — both are expensive mistakes.
Where Fora Soft fits in
We have built browser-side video players for nineteen years across the verticals where Video.js has historically been the default open-source choice — video conferencing platforms with on-platform recording playback, OTT and Internet-TV catalogues, e-learning courseware with timestamped quizzes, telemedicine consultation review, video surveillance dashboards with multi-stream walls, and AR/VR experiences that need a fallback flat-video player. The player is rarely the most visible part of the product, but it is one of the loudest indicators of engineering quality the moment a user hits play. Our practice in 2026 is to start a new client engagement by evaluating Video.js v10 + SPF, v10 + hls.js, Shaka Player, and the native iOS / Smart-TV path against the specific feature surface and DRM requirements of the project — the bundle-size and React-first arguments in this article tilt that evaluation toward v10 for most greenfield browser deployments, and the migration-cost argument tilts existing v8 deployments toward "stay through GA, plan the migration with intention".
What to read next
- hls.js in depth
- Shaka Player in depth
- Media Source Extensions (MSE): how every web player works under the hood
Call to action
- Talk to a streaming engineer — book a 30-minute scoping call to talk through your video.js v10 plan.
- See our case studies — 250+ shipped projects across video streaming, WebRTC, OTT, telemedicine, e-learning, surveillance, and AR/VR.
- Download the Video.js v10 evaluation checklist — One-page reference card: bundle-size comparison table, v10-vs-v8-vs-SPF decision tree, migration-readiness questions, yes-or-no recommendation grid.
References
- Video.js Project, Video.js v10 Beta: Hello, World (again), by Steve Heffernan, 10 March 2026. <https://videojs.org/blog/videojs-v10-beta-hello-world-again> — primary source for every bundle-size figure, feature description, and SPF framing in this article.
- Video.js Project, videojs/v10 repository on GitHub, accessed 2026-05-25. <https://github.com/videojs/v10> — primary source for the repository structure, the timeline (Technical Preview, Alpha Jan–Feb 2026, Beta Mar 2026, GA Mid 2026, Video.js parity End of 2026), and the agent-targeted files under
.claude/and.zed/. - Video.js Project, Concepts: Overview — three-part architecture, accessed 2026-05-25. <https://videojs.org/docs/framework/react/concepts/overview> — primary source for the State / Media / UI / Preset framing.
- Video.js Project, Concepts: Presets, accessed 2026-05-25. <https://videojs.org/docs/framework/react/concepts/presets> — primary source for the videoFeatures / audioFeatures / backgroundVideoFeatures preset taxonomy.
- Video.js Project, v10 Roadmap, accessed 2026-05-25. <https://videojs.org/docs/framework/react/concepts/v10-roadmap> — primary source for the v10 breaking-change list (cast → google-cast and remote-playback, fullscreen and pip unified on media capabilities, DelegateMixin / ProxyMixin replaced with MediaHost base classes).
- Video.js Project, VideoJS v10 — Big changes coming; input requested, discussion #9035, ongoing thread accessed 2026-05-25. <https://github.com/videojs/video.js/discussions/9035> — community discussion thread that surfaced the rewrite scope and the four-project merger.
- Mux, From Media Chrome to Video.js v10: The Evolution of HTML-First Video Players, 2026. <https://www.mux.com/blog/from-media-chrome-to-video-js-v10-the-evolution-of-html-first-video-players> — context for the Media Chrome → v10 merger and the rationale for HTML web components as a primitive layer.
- videojs/http-streaming (VHS), A Walk Through VHS, GitHub documentation, accessed 2026-05-25. <https://github.com/videojs/http-streaming/blob/main/docs/a-walk-through-vhs.md> — primary source for the legacy v8 streaming-engine architecture (VhsSourceHandler, PlaylistController) the v10 + SPF stack is replacing.
- W3C, Media Source Extensions — Candidate Recommendation Snapshot, latest revision 2024. <https://www.w3.org/TR/media-source-2/> — the browser API every streaming engine described in this article hands segments to. Cited normatively for MSE definitions; v10 + SPF and every other engine compared here are MSE clients.
- ISO/IEC 23000-19:2024, Common Media Application Format (CMAF) for segmented media, ISO/IEC catalogue. <https://www.iso.org/standard/87262.html> — the segment format SPF's beta "simple ABR" engine targets exclusively. Cited normatively for CMAF definition; spec text is paywalled, so this article relies on the abstract plus the open DASH-IF Implementation Guidelines that mirror CMAF usage.
- IETF RFC 8216, HTTP Live Streaming (HLS), R. Pantos, W. May, August 2017. <https://www.rfc-editor.org/rfc/rfc8216.html> — base specification for HLS, the format every engine compared in this article (v10 + SPF, v10 + hls.js, hls.js standalone, Shaka, legacy VHS) consumes. Apple HLS Authoring Specification revision 2025-09 layers normative requirements on top for the Apple ecosystem.
- ISO/IEC 23009-1:2022, MPEG-DASH — Dynamic adaptive streaming over HTTP, ISO/IEC catalogue. <https://www.iso.org/standard/83314.html> — base specification for MPEG-DASH, the second format v10 supports via external engines (Shaka, dash.js). Cited for completeness of the format-coverage row in the comparison table.
- Open Source For You, Video.Js V10 Delivers 81% Smaller Bundles Through Open Source Collaboration, March 2026. <https://www.opensourceforu.com/2026/03/video-js-v10-delivers-81-smaller-bundles-through-open-source-collaboration/> — secondary coverage that confirms the bundle-size headline number; this article uses the upstream announcement-post figures for every cell in the comparison table.
- Mux Blog, Video.js v10 Beta: Hello, World (again), mirror of the announcement post, 10 March 2026. <https://www.mux.com/blog/video-js-v10-beta-hello-world-again> — mirror of (1); cross-cited to confirm the announcement is reproduced unchanged on the project's sponsor blog.
- Matthijs Langendijk, A first look at the new Video.js v10 beta, March 2026. <https://mlangendijk.medium.com/a-first-look-at-the-new-video-js-v10-beta-cc2d0351f6b9> — first independent third-party walkthrough of the beta; treated as a competitor reference, not a source of truth for protocol claims.


