Skip to content
FrameworkStyle

Why Video.js?

The open-source video player for React and HTML. Lightweight, accessible components built for performance and streaming.

Video.js is the open-source video player for the web. It makes web video easy, performant, accessible, and customizable.

Let’s dig into when you’d want to use Video.js, starting with the the question we hear most…

Why not <video>?

The native <video> tag is great if you can describe your video as an image with a play button. Past that, the gaps show up quickly.

Cross-browser inconsistency

Chrome, Safari, and Firefox each render the default <video> controls differently. You can hide them, but you can’t deeply style or rearrange them. Building UI that matches your product means starting from scratch.

Chrome's default video controls
Chrome
Safari's default video controls
Safari
Firefox's default video controls
Firefox

Video interactions

Video often involves a lot more than an MP4 in src. Rich playback features (like thumbnail previews, adaptive bitrate, quality selection, chapters, audio track switching, control localization, error UI, live-streaming UI, analytics, ads, 360 video, Chromecast, AirPlay, DRM, and more) are possible with the video element but require complex wiring and deep consideration for maintainabilty and accessibility.

Video.js aims to handle this all out of the box. (Though some features are still under development. Stay tuned!)

Streaming formats and sources

Behind features like adaptive bitrate and quality selection are video formats like HLS or DASH — videos broken into segments that can be selected according to bandwidth and preferences. Not every browser supports HLS, and DASH support is even more limited. Video.js closes the gap so the same src works everywhere.

Of course, your video might not be coming from a src like that. It might be provided by a service. However, services like YouTube, Vimeo, and Mux each speak their own API. Switching from a self-hosted file to a hosted service shouldn’t mean switching players. Video.js abstracts the source so you can change where the video comes from without rewriting the surrounding code.

Video.js even considers sources like canvas-based MoQ or animated GIFs, all with the same components.

Why Video.js?

Video.js is built at Mux by the teams behind Video.js, Plyr, Vidstack, and Media Chrome, with contributions from engineers across other player projects. Between us, our projects have served tens of billions of monthly video plays. Most of the choices on this page came from things we got wrong the first time, then the second, then the fifth. We’ve been supporting your edge cases for over a decade. Now we’re shipping the player we always wanted to build.

Let’s dig into some of the design principles that help explain why we built Video.js and why it may be the best choice for your project or team.

Add only what you need

Most player libraries ship every feature in one bundle, so you carry code you don’t run. If your video doesn’t need a feature like DRM, why ship that code? Video.js turns features into independent, composable modules. You hand createPlayer the array you actually want, and what you don’t import doesn’t ship.

import { createPlayer, playbackFeature, timeFeature } from '@videojs/html';

const { ProviderMixin, PlayerController, context } = createPlayer({
  features: [playbackFeature, timeFeature],
});

Of course, you don’t have to think about every feature you’re going to need if you don’t want to. Pre-built feature bundles are still there if you’d rather not assemble the list by hand.

Framework-native

Many player libraries wrap a single web component for every framework. That works, until you reach the seams: refs you can’t pass through, state that doesn’t reconcile, prop names that aren’t quite React or HTML. Video.js ships idiomatic APIs in each framework: React components and hooks for React, custom elements and controllers for HTML. (And we plan on supporting more frameworks in the futrue!)

The player feels like the rest of your app.

import { Player, Video, VideoSkin } from '@videojs/react/video';

function MyPlayer() {
  return (
    <Player.Provider>
      <VideoSkin>
        <Video src="movie.mp4" />
      </VideoSkin>
    </Player.Provider>
  );
}

Eject and own

Most player libraries draw a line between “configurable through props” and “fork the source.” Cross the line and you’re on your own. Video.js lets you eject any skin and walk away with the source: components in your framework’s language that you can read and change. The skin you ship is yours; the rest of the player keeps working underneath it.

AI-native DX

Documentation aimed at human readers usually doesn’t help an agent. Video.js publishes an llms.txt index, ships every docs page as both HTML and Markdown, and has a dedicated guide for building with AI assistants. Drop the player into a Claude or Cursor session and the docs come along for the ride.