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 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 more than an MP4 in src. Features like thumbnail previews, adaptive bitrate, quality selection, chapters, audio track switching, localized controls, error UI, live-streaming UI, AirPlay, and DRM are possible with the video element, but require complex wiring and careful work on maintainability and accessibility.

Video.js provides accessible, composable building blocks for these common playback and streaming features. Other integrations, including ads and emerging media formats, remain under development as version 10 matures.

Streaming formats and sources

Behind features like adaptive bitrate and quality selection are streaming formats such as HLS and DASH. They split video into segments that a playback engine can select based on bandwidth and preferences. Choose the matching Video.js media component to play these formats across browsers while keeping the surrounding player state and UI consistent.

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. Video.js gives their media components a consistent interface, so changing providers doesn’t require rebuilding the player around them.

That boundary also gives us a path to future sources such as canvas-based MoQ playback and use cases such as animated GIF replacement without rebuilding the controls around them.

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/react';

const { Player } = 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 for its supported frameworks: React components and hooks for React, and custom elements and controllers for HTML.

The player feels like the rest of your app.

import { VideoPlayer, Video, VideoSkin } from '@videojs/react/video';
import '@videojs/react/video/skin.css';

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

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.

We don’t want to cram every possible player into one configuration API. Packaged skins cover common visual changes. For everything else, eject early and compose the UI you need.

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.