You need video on your site or in your app, and four names keep coming up: Video.js, Plyr, react-player and hls.js — with Mux Player joining the list if you stream from Mux. They’re all popular, all open source, and they solve different problems. This guide explains what each one actually is, shows the minimal setup code, compares them side by side and helps you pick the right one — or decide you don’t need a library at all.
Key takeaways
- Video.js — a full player framework with a large plugin ecosystem, skins and built-in HLS/DASH playback. Best when you need control and extensibility.
- Plyr — a lightweight player with a polished, accessible default UI for HTML5 video, YouTube and Vimeo. Best when you want a good-looking player fast.
- react-player — a React component that plays many URL types (files, YouTube, Vimeo and more) through one API. Best for React apps with mixed sources.
- hls.js — not a player UI but a streaming engine that adds HLS playback to browsers without native support. Pair it with the video tag or a player.
- Mux Player — a player made for video hosted on Mux, with analytics built in. Best if Mux is your video platform.
- If your goal is a gallery of YouTube, TikTok or Instagram videos on marketing pages, a ready-made widget is usually faster than any library.
What problem are you solving?
Before comparing features, be clear about the job. Most teams fall into one of four situations:
- Play your own MP4 files with a nicer UI than the browser default — Plyr or Video.js.
- Stream long videos or live video with adaptive quality (HLS/DASH) — Video.js, or hls.js plus your own UI, or the player of your video platform (for example Mux Player).
- Play URLs from many services in a React app — YouTube today, a Vimeo link tomorrow, an MP4 next week — react-player.
- Show many videos from YouTube, TikTok or Instagram as a gallery on a website — that’s not really a player problem; it’s a content and layout problem (see the last section).
The libraries at a glance
| Video.js | Plyr | react-player | hls.js | Mux Player | |
|---|---|---|---|---|---|
| What it is | Full player framework | Lightweight player UI | React wrapper for many sources | HLS streaming engine (no UI) | Player for Mux-hosted video |
| License | Apache 2.0 | MIT | MIT | Apache 2.0 | MIT |
| HTML5 video files | Yes | Yes | Yes | Via the video element | Mux assets |
| YouTube / Vimeo | Via plugins | Built in | Built in | No | No |
| HLS | Built in (VHS) | With hls.js | Uses hls.js for .m3u8 | Yes — its purpose | Yes |
| DASH | Built in (VHS) | With a DASH library | Via a file player plugin | No | — |
| Captions | Yes | Yes | Depends on source | Your player handles them | Yes |
| Skins / theming | CSS skins, themes, plugins | CSS variables | Source’s own UI | — | CSS variables, themes |
| React support | Via a wrapper component | Via a wrapper | Native | Any framework | @mux/mux-player-react |
| Best for | Control, plugins, streaming | Fast, clean default UI | Mixed URLs in React | HLS in Chrome/Firefox/Edge | Teams on Mux |
Video.js
Video.js is the veteran of open source video players. It wraps the HTML5 video element in a consistent, customizable UI and adds a plugin system that covers everything from quality selectors to analytics and ads. Its built-in streaming engine (VHS) plays both HLS and DASH, so you rarely need extra libraries for adaptive streaming — Video.js HLS playback works out of the box.
Install and set up
npm install video.js
import videojs from "video.js";
import "video.js/dist/video-js.css";
const player = videojs("my-video", {
controls: true,
fluid: true,
sources: [{ src: "https://example.com/stream.m3u8", type: "application/x-mpegURL" }]
});
<video id="my-video" class="video-js" playsinline></video>
Video.js with React
This is the standard Video.js React pattern. Create the player in an effect and dispose it on unmount — otherwise route changes leave players running in memory.
import { useEffect, useRef } from "react";
import videojs from "video.js";
import "video.js/dist/video-js.css";
export function Player({ src }: { src: string }) {
const ref = useRef<HTMLVideoElement>(null);
useEffect(() => {
const player = videojs(ref.current!, { controls: true, fluid: true, sources: [{ src }] });
return () => player.dispose();
}, [src]);
return <video ref={ref} className="video-js" />;
}
Skins and themes
Video.js ships with a default skin you can restyle with CSS. Official and community themes (and plugins for things like playlists or quality menus) let you change the look without rebuilding the controls. If you need a strongly branded player, plan time for CSS work — Video.js gives you all the hooks, but the polish is up to you.
When to choose Video.js
- You stream HLS or DASH and want one library that does both.
- You need plugins: analytics, ads, quality switching, playlists.
- You want a mature project with a long track record and a large community.
Plyr
The Plyr video player (often searched as “Plyr JS”) focuses on one thing: a beautiful, accessible player that works out of the box. It supports HTML5 video and audio plus YouTube and Vimeo embeds behind the same UI, and it’s styled with CSS custom properties, so matching your brand colors takes minutes. Plyr doesn’t stream HLS by itself — pair it with hls.js for that.
Install and set up
npm install plyr
import Plyr from "plyr";
import "plyr/dist/plyr.css";
const player = new Plyr("#player", {
controls: ["play-large", "play", "progress", "current-time", "mute", "volume", "captions", "fullscreen"]
});
<video id="player" playsinline controls poster="poster.jpg">
<source src="clip.mp4" type="video/mp4">
</video>
<!-- or a YouTube video behind the same UI -->
<div id="player" data-plyr-provider="youtube" data-plyr-embed-id="VIDEO_ID"></div>
Plyr with HLS
const video = document.querySelector("video");
const hls = new Hls();
hls.loadSource("https://example.com/stream.m3u8");
hls.attachMedia(video);
const player = new Plyr(video);
When to choose Plyr
- You want a clean, modern player with good keyboard and screen reader support and little setup.
- You mix your own files with YouTube or Vimeo and want one consistent UI.
- You don’t need a big plugin ecosystem.
react-player
react-player (the npm package many people search for simply as “react player”) is a React component that accepts a URL and figures out how to play it: an MP4 file, an HLS stream, a YouTube or Vimeo link and several other services. It doesn’t replace each service’s player — it embeds it — but it gives you one consistent React API for playing, pausing, seeking and listening to events.
Install and use
npm install react-player
import ReactPlayer from "react-player";
export function Hero() {
return (
<ReactPlayer
url="https://www.youtube.com/watch?v=VIDEO_ID"
controls
width="100%"
height="100%"
/>
);
}
Note: check the documentation for the major version you install — recent versions renamed some props. The idea stays the same: one component, many sources.
When to choose react-player
- Your React app plays URLs from different services.
- You want a quick, declarative API rather than building a player.
- You’re fine with each service’s own player UI inside the component.
hls.js
hls.js is a JavaScript library that plays HLS (HTTP Live Streaming) in browsers that don’t support it natively, using Media Source Extensions. It has no UI — you attach it to a <video> element or to a player such as Plyr. Safari plays HLS natively, so you only need hls.js for Chrome, Firefox and Edge.
Install and set up
npm install hls.js
import Hls from "hls.js";
const video = document.querySelector("video");
const src = "https://example.com/stream.m3u8";
if (Hls.isSupported()) {
const hls = new Hls();
hls.loadSource(src);
hls.attachMedia(video);
} else if (video.canPlayType("application/vnd.apple.mpegurl")) {
video.src = src; // Safari plays HLS natively
}
Documentation and demo
The hls.js project publishes API documentation and a live hls.js demo page where you can paste a stream URL and inspect quality levels, buffering and errors — useful for debugging a stream before you build anything around it.
When to choose hls.js
- You have HLS streams and want them to play everywhere.
- You already have a UI (or use Plyr) and just need the streaming engine.
- You want fine control over buffering and quality switching.
Mux Player
If you host video on Mux, Mux Player is the natural choice: a web component (with a React version) that plays Mux streams with adaptive quality and sends viewing data to Mux’s analytics. It’s themeable and handles captions, thumbnails and timelines for you. It’s less useful if your video lives elsewhere.
npm install @mux/mux-player-react
import MuxPlayer from "@mux/mux-player-react";
<MuxPlayer playbackId="YOUR_PLAYBACK_ID" metadata={{ video_title: "Product demo" }} />
HLS and DASH in two paragraphs
HLS and DASH split a video into short segments at several quality levels and describe them in a manifest file (.m3u8 for HLS, .mpd for DASH). The player downloads segments one by one and picks the quality that fits the viewer’s connection — that’s adaptive streaming, and it’s why long videos start fast and don’t stall.
If you only have short MP4 files, you don’t need any of this: the HTML5 video element plays them everywhere. Streaming matters for long videos, live video and large audiences — and in those cases most teams use a video platform that encodes the streams for them.
Performance: how not to slow your site down
- Load players only where needed. Import the library on pages that actually have video, ideally with a dynamic import when the player scrolls into view.
- Start with a poster. Show a lightweight thumbnail and create the player on click — especially when a page has several videos.
- Reserve space. Set
aspect-ratioon the container so the page doesn’t jump when the player loads (Cumulative Layout Shift). - Use
preload="metadata"for files so the browser doesn’t download the whole video up front. - Stream long videos instead of serving one large MP4.
Accessibility checklist
- Captions for every spoken video (WebVTT tracks).
- Full keyboard control: play/pause, seek, volume, fullscreen.
- Visible focus states and labelled buttons for screen readers.
- No autoplay with sound; respect
prefers-reduced-motionfor background video.
Plyr and Video.js both take accessibility seriously, but test with a keyboard and a screen reader either way — custom skins can break what the defaults get right.
Decision guide
| If you need… | Choose |
|---|---|
| A polished default player for MP4, YouTube and Vimeo | Plyr |
| Plugins, skins, analytics hooks, HLS and DASH out of the box | Video.js |
| Many URL types in a React app with minimal code | react-player |
| HLS in Chrome, Firefox and Edge with your own UI | hls.js |
| Playback and analytics for video hosted on Mux | Mux Player |
| A gallery of YouTube, TikTok, Instagram or Vimeo videos on a marketing page | A gallery widget (see below) |
When a library is overkill
Player libraries give you a player. If what you actually need is a video section — your YouTube channel, a playlist of tutorials, customer testimonials from TikTok and Instagram — you’d still have to build the gallery layouts, fetch the videos from each platform’s API (with keys and quotas), keep the feed up to date and give your team a way to manage it.
Elfsight Video Gallery does that part for you: connect YouTube, Vimeo, TikTok, Instagram Reels, Twitch or any video link, pick one of seven layouts, and add it to any website — or to a React app with the official react-elfsight-widget component. New videos appear automatically, videos open in a popup on your page, and you can show a call-to-action card after each video.
See how it works for React and Next.js.
Frequently asked questions
What is the best open source video player?
For most websites, Video.js (full-featured, plugins, streaming) or Plyr (lightweight, polished UI). Pick Video.js if you stream HLS/DASH or need plugins; pick Plyr if you want a great default look with little setup.
Is Video.js free?
Yes. Video.js is open source under the Apache 2.0 license.
Can Plyr play YouTube and Vimeo?
Yes. Plyr supports YouTube and Vimeo embeds as well as HTML5 video and audio, all behind the same UI.
Do I need hls.js with Video.js?
Usually not. Video.js includes its own streaming engine (VHS) for HLS and DASH.
Do I need hls.js in Safari?
No. Safari plays HLS natively. hls.js is for browsers without native HLS support.
Does react-player support HLS?
Yes. For .m3u8 URLs it uses hls.js under the hood.
What is the best React video player?
react-player if you play URLs from different services; Video.js with a React wrapper if you need full control and streaming; Mux Player React if your video is on Mux.
What’s the difference between a video player and a video player SDK or API?
A player library gives you the UI and playback. A video platform’s SDK or API also handles uploading, encoding, streaming and analytics. If you only need playback of files you already host, a library is enough.
Which video player is lightest?
Among full player UIs, Plyr is the lightest. hls.js is smaller still, but it’s only a streaming engine and needs a video element or player on top.
How do I add a gallery of YouTube videos to a React app without a player library?
Use a widget: create a video gallery in Elfsight, connect your channel or playlist and render it with react-elfsight-widget. No API keys, no player code.

