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
Replace Plyr’s constructor and options object with a Video.js player, media component, and skin. Read playback and UI state through player state.
Start with the Neutral skin, move media settings into markup, and replace calls to the Plyr instance with native media APIs or Video.js store actions.
AI Quickstart
Paste this prompt into your coding agent:
Migrate this project's Plyr player to Video.js v10 for HTML. Use @videojs/html or its CDN bundles for a page without a build step.
Run `npx @videojs/cli agents skills` to get the Video.js skill installation instructions. Follow the printed steps for your agent. If they require a session reload, reload the session and continue with this prompt. If you can't run commands, use the installation instructions at https://github.com/videojs/skills. Use the skill throughout this migration.
Read the migration guide at https://videojs.org/docs/framework/html/guides/migrate-from-plyr, including its Known gaps section. Inspect the existing player and list its media URLs, source formats, tracks, options, custom controls, event handlers, and integrations. Compare that list with the known gaps and report unsupported requirements before changing code. Keep the existing media URLs and required behavior throughout the migration.
For installation guidance, read https://videojs.org/docs/framework/html/llms.txt and follow its link to the installation guide. Keep using that online index for a CDN installation.
From the application root, run `npx @videojs/cli agents init` without flags to list installation options and their accepted values.
Choose values for these options:
- --media and --source-url: the existing content and playback requirements.
- --method: the installation method.
- --preset, --skin, and --extensions: the player UI and integrations.
Add those options to `npx @videojs/cli agents init --framework html --project existing` and run the command to print the installation plan. Follow any version-mismatch notice. Both CLI commands print instructions without changing project files. Use the printed plan to install Video.js and configure the player.
After installing a package, switch to node_modules/@videojs/html/docs/llms.txt for documentation matching its version.
Implement the migration. Then verify playback, captions, controls, and any analytics integration on every browser the project supports.What changes
- Player, media, and skin are separate. Put source settings on the media, poster metadata on the player, and controls in the skin.
- HLS and DASH need a streaming media component. Keep the playback engine your app requires; see Streaming.
- Controls are composed in a skin. To migrate Plyr’s
controls, hotkeys, or gestures, edit skin source. - Casting needs setup. The video skins include AirPlay and Cast buttons. The Cast button needs the Google Cast extension. Follow Cast to AirPlay and Chromecast.
Basic migration
Start with a Plyr player that has captions, thumbnail previews, and a poster:
The Neutral skin is the closest built-in starting point for this migration.
For an HTML page without a bundler, load the CDN preset:
For a bundler installation, install the HTML package and import the player and skin:
Notes
- The skin adds its styles to its own shadow root. You do not link a stylesheet.
- Remove
controlsfrom the media so the browser’s native controls do not appear beside the skin’s controls. - The poster moves from
data-posteron the media toposteron<video-player>. The skin reads that value and controls how the poster appears. To supply your own image element, see Add a poster and loading placeholder. - To use the Default skin, change
<video-neutral-skin>to<video-skin>. From the CDN, loadvideo.jsinstead ofvideo-neutral.js. With a bundler, replace the Neutral skin import with@videojs/html/video/skin.
If caption or thumbnail tracks come from a different origin than the page, set crossorigin="anonymous" on the media (crossOrigin="anonymous" in React). Also serve the media and track files with CORS headers that allow your page’s origin. See Thumbnail.
Map common features
Streaming
For HLS or DASH, replace the native video component with a media component for that format. Check that the component’s engine supports your stream before you choose it.
HLS
If your Plyr integration uses hls.js, keep it by using the hls.js video component. The installation CLI’s --media hls option selects this component.
The SPF HLS video component is an alternative for fMP4/CMAF streams. It does not support MPEG-TS segments, raw ADTS AAC, or whole-segment AES-128 encryption. It supports DRM through source.drm. Verify your license configuration and browser support with the engine you choose before switching.
Replace <video> with <hlsjs-video>. If you’re using the CDN, add an additional script:
For a bundler installation, install the adapter package and add the media import:
Set src to your .m3u8 manifest URL.
DASH
Use the DASH media component for an unprotected DASH source. For DRM-protected DASH, use Shaka video and configure source.drm; the dash.js component has no DRM configuration input. See the DRM migration example.
Replace <video> with <dash-video>. If you’re using the CDN, add an additional script:
For a package-manager installation, install the DASH adapter package and add the media import:
Set src to your .mpd manifest URL.
Vimeo
Use the Vimeo media component for your existing Vimeo source.
Replace <video> with <vimeo-video>. For a CDN installation, add the media script:
For a bundler installation, install the adapter package and add the module import:
Set the src to the URL for the Vimeo video, for example https://vimeo.com/76979871.
YouTube
Use the YouTube media component for your existing YouTube source.
Replace <video> with <youtube-video>. For a CDN installation, add the media script:
For a bundler installation, install the adapter package and add the module import:
The component accepts YouTube watch, youtu.be short-link, embed, Shorts, live, playlist, and privacy-enhanced (youtube-nocookie.com) URLs, as well as raw 11-character video IDs.
Internationalization
Video.js defaults to English. To migrate Plyr’s i18n strings, register translation overrides or pass them to a provider. For shipped locales and language selection, follow Internationalize the player.
To select a locale, wrap the player in <media-i18n> and set lang to your locale tag, such as lang="ja". The CDN preset registers this element. With a bundler, import @videojs/html/i18n to register it. For English overrides from the CDN:
With a bundler, import registerI18n from @videojs/html/i18n.
Configuration
Move media options to attributes or props. For controls and interactions, use a skin or edit its installed source. Where the table says to edit local skin source, it means those installed files:
When enabling captions without a previous selection in this player instance, toggleSubtitles() prefers a track matching navigator.language, then falls back to the first available caption or subtitle track. For an authored track that should show on load, add default. See Show captions and subtitles.
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. A component you add as a child of a packaged skin does not appear in its 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
Use store actions for playback, seeking, volume, fullscreen, and captions:
Plyr’s volume setter unmutes for values above zero, as setVolume does. Set media.volume directly only when you intend to preserve mute state.
If the volume is 0, setMuted(false) also sets it to 0.25. To unmute and keep a zero volume, set media.muted directly.
Native media methods and properties also update player state through media events. To change content, set src on the media component. If the new source needs a different playback engine, replace the element, such as moving from <video> to <hlsjs-video>. The player UI follows the attached media.
Call store actions after the player is defined and media is attached:
To keep a custom element in sync with player state, use PlayerController:
Render it inside your existing <video-player> so it can read that player’s state:
Rewrite styles
Like Plyr, Video.js skins let you customize colors with 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 for content on the accent color. To choose that text color yourself, set --media-accent-text-color. --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 TypeScript components and styles become local files that need a build step. A CDN-only page must add a build step before it can use this source. 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. For application-managed persistence, follow Remember user preferences. - Playback rates are fixed at
0.2,0.5,0.7,1,1.2,1.5,1.7, and2. Plyr’sspeed.optionshas no equivalent yet (#1404). - Plyr’s full-window fullscreen fallback has no matching Video.js feature. Test fullscreen on your supported browsers; see Browser support.
- Plain MP4 source arrays with
sizemetadata do not automatically create a quality menu. Use Mux, HLS, or DASH for adaptive quality when possible. - Preset skins segment the time slider and show chapter titles when the media includes a default
<track kind="chapters">. Cue points are not implemented yet; see #1442. - The controls auto-hide delay is not configurable yet (#1728). To disable auto-hide, set
visibility="always"on the controls component in a custom layout or installed skin source. Packaged skins do not expose this setting. - Native controls are not automatically removed when custom controls load; see #1160.