GuideMigrate
Migrate from Plyr
Move an existing Plyr integration to Video.js v10, mapping Plyr options and its instance API onto components and player state
Video.js v10 is not a drop-in replacement for Plyr. Plyr wraps one media element with a constructor and options object. Video.js composes a player, media component, and skin in markup, then exposes behavior through player state.
Start with the Minimal skin, move media settings into markup, and replace calls to the Plyr instance with native media APIs or Video.js state actions.
What changes
- The player becomes three pieces. Player state, the media component, and the skin are separate, so you can replace one without wrapping or forking the others.
- Streaming behavior becomes player state. HLS, DASH, and Mux integrations expose renditions, tracks, and live state to the UI instead of leaving that wiring to application code.
- The UI is composable. Buttons, sliders, menus, gestures, and hotkeys are individual accessible components. Start with the Minimal or Default skin, then add its source to your project when you need to change the structure.
- Remote playback is built in. The video skins include AirPlay and Cast controls. Follow Cast to AirPlay and Chromecast to add the Google Cast extension.
Basic migration
Start with a Plyr player that has captions, thumbnail previews, and a poster:
The Minimal skin is the closest built-in starting point for this migration.
The easiest path is the CDN:
If you prefer not to use the CDN, you can use the individual modules:
Notes
- The skin attaches its styles automatically to its shadow root.
- The poster moves from
data-posteron the media toposteron<video-player>. The skin reads that value and controls how the poster appears. For more advanced control (like supplying your own image element), see Add a poster and loading placeholder. - There’s also a default skin with a modern, frosted appearance that some may prefer. Try it by removing the
-minimalsuffix from the scriptsrcif you’re using the CDN, or theminimal-prefix from the imports.
Map common features
Streaming
If you’re using HLS or DASH to stream your media, you’re in luck; we have prebuilt media components you can slot in with much improved integration over Plyr implementations.
HLS
Replace <video> with <hls-video>. If you’re using the CDN, add an additional script:
For a package-manager installation, install SPF and add its façade import:
Set the src to the URL for the m3u8 manifest.
DASH
Very similar to HLS in that we have a drop-in component.
Replace <video> with <dash-video>. If you’re using the CDN, add an additional script:
For a package-manager installation, install dash.js and add its façade import:
Set the src to the URL for the mpd manifest.
Vimeo
Vimeo is supported through a prebuilt component.
Replace <video> with <vimeo-video> and add the module import:
Set the src to the URL for the Vimeo video, for example https://vimeo.com/76979871.
YouTube
YouTube is supported through a first-class media component.
Replace <video> with <youtube-video> and add the module import:
The component accepts YouTube watch, short, embed, Shorts, live, playlist, and privacy-enhanced URLs, as well as raw 11-character video IDs.
Internationalization
Video.js v10 ships with English labels by default and includes locale packs for:
ar, az, bg, bn, bs, ca, cs, cy, da, de, el, es, et, eu, fa, fi, fr, gd, gl, he, hi, hr, hu, id, it, ja, ko, lt, lv, mr, nb, ne, nl, nn, oc, pl, pt-BR, pt-PT, ro, ru, sk, sl, sr, sv, te, th, tr, uk, vi, zh-CN, and zh-TW.
The shorthand tags pt and zh are also available as aliases. See Internationalize the player for the full picture.
For CDN users:
For package users, same idea but import from @videojs/html/i18n.
Configuration
Plyr uses an object to set configuration options whereas Video.js v10 uses a component structure and attributes instead. We’re using a composition model rather than a configuration model. This reduces bundle size and only includes functionality you actually require.
Here’s a matrix for configuration options in Plyr and how each maps to Video.js v10:
Customize the controls
Plyr’s controls option chooses which controls appear. Video.js skins come with their own control set and layout. Keep the skin when that UI fits your player. To remove, reorder, or restyle its controls, add the skin source to your project and edit it. Adding a child to a skin does not place it inside the control bar.
If your app already has a custom control bar, build it from individual UI components. Video.js handles the media action, accessible name, and state. You add the visible contents, layout, and CSS.
Individual HTML buttons include no text, icon, or finished styling. Add your own content, or import @videojs/html/icons/element and place a <media-icon> inside the button. Attach click handlers directly to controls you add, and keep playback event handlers on the <video> or <audio>. To change or listen to a button inside a ready-made skin, add the skin source to your project first.
Use the imperative API
Control everything through the player’s store. Every Plyr call has a matching store action, so one mental model covers playback, volume, fullscreen, and captions alike:
You can still script the media element directly when you want to. Plyr routed calls through its wrapper because the wrapper had to know about every change; Video.js derives player state from the native media events, so video.play() or video.currentTime = 10 keeps every control in sync. The media element is also the way to change content: set src on the media component to swap sources, and replace the component when the media type changes, such as moving from <video> to <hls-video>. The player UI follows the attached media.
The store’s actions live on the player element’s store.state: query <video-player> and call player.store.state.togglePaused(). Your media element is also a plain child in your markup, so you can query and drive it directly. To keep a custom element in sync with player state, use PlayerController:
Rewrite styles
Video.js v10 skins offer similar color customization via CSS custom properties. Add the skin source to your project when you need deeper control over layout, control structure, icons, or interaction styling.
--media-accent-color reaches the sliders, active buttons, and accent surfaces, so it’s the closest match for Plyr’s --plyr-color-main. Video.js picks a readable text color to sit on top of it; set --media-accent-text-color to choose that yourself. --media-border-radius and --media-scale-unit cover rounding and control sizing. See Customize skins for the full list.
Edit skin source
For changes to controls, layout, or icons, add the skin source to your project. Its components and styles become local files. Customize skins covers the setup and available skins.
Known gaps
- Plyr’s
adsoption has no built-in equivalent. - Plyr’s
storageoption has no built-in equivalent for persisted volume, captions language, muted state, speed, or quality. Player setting persistence is tracked in #944; subtitle language preference is tracked in #1423. - Plyr’s full-window fullscreen fallback has no matching Video.js feature. This was designed as a fallback when the Fullscreen API wasn’t supported, but given browser support for fullscreen is around 96%, it’s unlikely to be required.
- Plain MP4 source arrays with
sizemetadata do not automatically create a quality menu. Use Mux, HLS, or DASH for adaptive quality when possible. A simpler source-driven quality menu may be considered later. - Preset skins segment the time slider and show chapter titles when the media includes a default
<track kind="chapters">. Dedicated cue-point APIs are not complete yet; see #1442. - The controls auto-hide delay is not configurable yet (#1728). Disabling auto-hide is possible with
visibility="always"on the controls component, but not from a preset skin’s attributes. - Native controls are not automatically removed when custom controls load; see #1160.