plyr-react is a thin React wrapper, and that is its main design decision
A simple, accessible and customisable react media player for Video, Audio, YouTube and Vimeo
At a glance
- What is it?
- plyr-react exposes the Plyr HTML5 media player to React through a component and a hook, with TypeScript types, refs that give you the raw player instance, and a CSS import path that changed at v5. The wrapper is deliberately small, which is both its strength and its limit.
- Who is it for?
- Adopt plyr-react if you want Plyr's accessible player UI in a React application without writing the glue yourself, and you are on React 16.8 or newer with Node 16 or newer. Do not adopt it if you need a player with no Plyr underneath, since the wrapper adds no rendering of its own and every behaviour change still means going around it.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 32 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A wrapper over Plyr, and the two ways to use it
plyr-react is described as a responsive media player that is simple, easy to use and customizable for video, audio, YouTube and Vimeo. It wraps the Plyr media player and gives React applications a way to embed video, audio, YouTube and Vimeo content.
Two entry points, and the choice between them is the whole API design.
The simple one is the `<Plyr />` component, which is the simplest way to get started for most use cases. You pass a source and an options object and you get a player.
import Plyr from "plyr-react"
import "plyr-react/plyr.css"
function MyPlayer() {
return <Plyr {...plyrProps} />
}The advanced one is the `usePlyr` hook, which the documentation recommends for full control over the player's lifecycle and integration, because it allows you to build a completely custom component wrapper. The example in the docs is explicit that it re-creates the `<Plyr />` component using the hook.
import { usePlyr } from "plyr-react"
import "plyr-react/plyr.css"
const CustomPlyr = React.forwardRef((props, ref) => {
const { source, options = null, ...rest } = props
const raptorRef = usePlyr(ref, {
source,
options,
})
return <video ref={raptorRef} className="plyr-react plyr" {...rest} />
})The hook returns a ref you attach to a `<video>` or `<div>` element, and it takes the same source and options as the component. So the hook is not a different feature set, it is the same player with the wrapper removed.
The badges make the packaging claim explicit: the build is tree shakeable and side effect free, which is also why the package.json sets sideEffects to false.
The ref is the escape hatch, and it hands you Plyr itself
The third usage pattern is the one that decides whether this wrapper fits your project, and it is the programmatic access through refs.
The ref gives access to the full Plyr API, and the ref's `current` object contains a `plyr` property which is the player instance. So you are not talking to a React-shaped abstraction, you are holding the actual Plyr object.
import React, { useRef, useEffect } from "react"
import Plyr from "plyr-react"
import "plyr-react/plyr.css"
const PlayerController = () => {
const ref = useRef(null)
const playVideo = () => {
// ref.current.plyr is the Plyr instance
if (ref.current && ref.current.plyr) {
ref.current.plyr.play()
}
}
const enterFullscreen = () => {
if (ref.current && ref.current.plyr) {
ref.current.plyr.fullscreen.enter()
}
}That distinction matters more than it first appears. Because the escape hatch exposes the underlying library, the wrapper does not lock you into a subset of Plyr's API. You can call `fullscreen.enter()` and any other Plyr method, and the documentation's own examples do exactly that.
The cost is that the abstraction stops there. The wrapper's typing covers props, options and the player instance, and it exports types for each of those, but the moment you go through `ref.current.plyr` you are using Plyr's own API and your own knowledge of it. The wrapper saves you the lifecycle wiring, not the learning curve.
For a team that already knows Plyr, that is exactly the right division of labour. For a team that does not, you will be reading Plyr's documentation anyway.
Peer dependencies, the CSS path, and the Node floor
Installing this is straightforward, and the part that catches people out is the peer dependencies.
You install the package with npm, yarn or pnpm.
npm install plyr-reactBut plyr-react does not bundle React or Plyr. The peer dependencies are react at version 16.8 or newer, and plyr at version 3.7.7 or a compatible version, and you must ensure these are listed in your project's package.json. Most package managers will warn you if they are missing.
npm install react react-dom plyrThe React 16.8 floor is not arbitrary: that is the version where hooks arrived, and the usePlyr hook is built on them. The system requirements list Node.js version 16 or higher, and React version 16.8 or higher.
The second trap is the stylesheet. You must import the stylesheet to apply the default player theme, and the import path changed at v5.0.0. As of v5.0.0 the CSS import path is `plyr-react/plyr.css`, and for older versions, v4, you must use `plyr-react/dist/plyr.css`.
That change is visible in the package.json exports, which map `./plyr.css` to `./dist/plyr.css` and give the package a root export with import, require and types conditions. The exports map is why the bare `plyr-react/plyr.css` path resolves at all, and it is why the v4 path is a different string entirely.
The releases show the two eras clearly: v5.3.0 from 2023-06-13, then v6.0.0-2 in November 2025 and v6.0.0 in December 2025, with the last push to the repository on 2026-09-21.
What you get in the box, and what you have to supply
The feature list is a list of things Plyr already does, with two additions of its own, and reading it that way is the fairest interpretation.
Broad media support is native support for HTML5 video and audio elements as well as embedded players from YouTube and Vimeo. Deep customization is the rich set of options controlling every aspect of the player UI and behavior, including controls, settings menus and event listeners. Accessibility is described as built on the accessible foundation of the underlying Plyr player, which is the correct way to put it: the wrapper inherits the accessibility work rather than adding to it. And streaming support means it can be integrated with libraries like HLS.js for adaptive bitrate streaming.
The two additions are the React-specific ones. The modern React API gives you a simple component for quick setup and a usePlyr hook for full control and custom logic. And TypeScript support is fully typed, with exported types for props, options and the player instance.
What you have to supply is worth stating plainly. The stylesheet, which you import yourself. The peer dependencies, react and plyr. And, if you want adaptive streaming, an integration with HLS.js that this package does not perform for you, since the wording is that it can be integrated with streaming libraries like HLS.js.
So the wrapper covers the React lifecycle, the typing and the option plumbing. Everything else is Plyr, and the honest description of the package is that it makes Plyr usable from React without reimplementing anything.
Where plyr-react is the wrong choice
Three cases, and the first is the one that decides most of them.
If you do not want Plyr, this does not help. There is no alternative renderer hidden inside the wrapper. The options you pass are Plyr's options, the class names on the element come from Plyr's theme, and the accessibility behaviour is Plyr's. If your objection is to Plyr's markup or its controls, you would have to replace the whole thing, at which point you are not using this package.
The second is if you need a player with no Plyr at all, such as a video editor with frame-accurate scrubbing, or a player with custom transport controls. A hook that gives you the underlying library instance is useful for integration, and it is not a starting point for building a different player.
The third is if your build cannot handle the packaging. The package is an ES module with a `type` field of module, the main entry is a CommonJS file at `./dist/index.cjs` and the module entry is `./dist/index.js`, and the build runs tsdown with the rolldown config. The exports map has separate import, require and types conditions, which modern bundlers handle, and the published files are just the dist directory. An older toolchain that resolves dependencies by file path rather than by exports map can trip over that, and the CSS export in particular needs the exports map to resolve.
One more practical note about the versions. The v5 to v6 transition moved the CSS import path, and a project that upgrades the package without updating its import will get a missing stylesheet and an unstyled video element rather than an error. That is an easy fix once you know about it and a confusing one if you do not.
Maintenance, licensing and the build tooling behind it
The repository is not archived and the last push was on 2026-09-21, so the code is being worked on. The recent releases are v6.0.0 from 2025-12-20, v6.0.0-2 from 2025-11-07 and v5.3.0 from 2023-06-13.
The licence is MIT, recorded in the package.json and with the LICENSE file at the top of the repository. The homepage in the package metadata points at the GitHub repository, and the author is Chintan Prajapati.
The tooling is worth a note because it tells you what a contributor is expected to have. The build is tsdown driven by a rolldown.config.ts, with a dev script running the same config in watch mode. Linting is eslint over src and tests with a flat config, tests run on jest with swc for transformation and testing-library for React, and there is a husky prepare hook plus a .lintstagedrc.json and a .pre-commit-config.yaml for pre-commit checks. There is also a .swcrc, a .prettierrc, a .typo-ci.yml for spell checking and a sonar-project.properties file, which means static analysis results are tracked as part of the build.
The repository also has a SECURITY.md, a CODE_OF_CONDUCT.md, a CONTRIBUTING.md and a CHANGELOG.md, and an example directory with a plyr-example subdirectory.
One dependency detail explains the architecture. The only runtime dependency is react-aptor at ^2.0.0, a small React adapter library, and the hook example imports it implicitly through the usePlyr hook. The wrapper is thin enough that its entire runtime surface is one adapter package, which is a good sign for tree shaking and for the size of what ends up in your bundle.
Editorial conclusion
Adopt plyr-react if you want Plyr's accessible player UI in a React application without writing the glue yourself, and you are on React 16.8 or newer with Node 16 or newer. Do not adopt it if you need a player with no Plyr underneath, since the wrapper adds no rendering of its own and every behaviour change still means going around it. Verify first that your build tool handles the CSS export path, because the stylesheet moved to plyr-react/plyr.css at v5.0.0 and the older plyr-react/dist/plyr.css path is for v4 only.
Frequently asked questions
How do I install plyr-react?
Run npm install plyr-react, or the yarn or pnpm equivalent. You also have to install the peer dependencies yourself: react at version 16.8 or newer and plyr at version 3.7.7 or a compatible version. Node.js version 16 or higher is required.
What is the difference between the Plyr component and the usePlyr hook in plyr-react?
The <Plyr /> component is the simplest way to get started, while the usePlyr hook is the recommended approach for full control over the player's lifecycle and integration. The hook returns a ref you attach to a video or div element and takes the same source and options as the component, so it removes the wrapper rather than adding features.
How do I control the player from my own code in plyr-react?
Pass a ref to the component. The ref's current object contains a plyr property holding the player instance, so you can call methods such as ref.current.plyr.play() or ref.current.plyr.fullscreen.enter() directly.
Where does the plyr-react stylesheet go?
Import plyr-react/plyr.css, which is the path as of v5.0.0. For older versions, v4, the path is plyr-react/dist/plyr.css. The stylesheet has to be imported for the default player theme to apply.
Is plyr-react tree shakeable and free of side effects?
Yes. The project describes its build as tree-shakeable and side-effect free, and the package.json sets sideEffects to false. The only runtime dependency is react-aptor at ^2.0.0.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/chintan9-plyr-react)Was this useful?