Skip to content
FrameworkStyle

Skins

Packaged player designs that include both UI components and their styles.

A skin wraps the media component and provides the player’s complete interface. It combines a specific set of UI components with the styles that arrange and present them.

Packaged and ejected skins

When you choose a skin you have two options for how you use it: packaged or ejected. It’s usually easiest to start with a packaged skin and later eject its internal components into your project when you need more customization.

Packaged skins cover common visual changes through documented CSS custom properties. Packaged video skins also let you replace the poster. When you need more than that, eject and change the components and styles directly.

Packaged Ejected
Single component Many UI components
Documented CSS custom properties Components and styles you own
Future design updates auto-applied by bumping the version Future design updates manually applied, or intentionally ignored

Packaged skin

<script type="module">
  import '@videojs/html/video/player';
  import '@videojs/html/video/skin';
</script>

<video-player>
  <video-skin>
    <video src="video.mp4"></video>
  </video-skin>
</video-player>

Don’t depend on elements, class names, or undocumented custom properties inside a packaged skin. They may change between releases.

Ejected skin

An ejected skin exposes its UI components and styles as app code that you own. You can add, remove, rearrange, or restyle any part of it.

<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/html@10.0.0-beta.32/cdn/video.js"></script>
<link rel="stylesheet" href="./player.css">

<video-player poster="https://image.mux.com/BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM/thumbnail.webp">
  <media-container class="media-container media-skin media-skin--video">
  <slot>
  </slot>
  <media-poster class="media-poster">
  <img alt="" decoding="async" />
  </media-poster>
  <media-buffering-indicator class="media-buffering-indicator">
  <span class="contents theme-minimal:hidden">
  <media-icon name="spinner" class="media-buffering-indicator-spinner-icon">
  </media-icon>
  </span>
  <span class="hidden theme-minimal:contents">
  <media-icon family="minimal" name="spinner" class="media-buffering-indicator-spinner-icon">
  </media-icon>
  </span>
  </media-buffering-indicator>
  <media-error-dialog class="media-dialog-root">
  <media-dialog-backdrop class="media-dialog-backdrop">
  </media-dialog-backdrop>
  <media-dialog-popup class="media-dialog-popup">
  <div class="media-dialog-content">
  <media-dialog-title class="media-dialog-title">
  </media-dialog-title>
  <media-dialog-description class="media-dialog-description">
  </media-dialog-description>
  </div>
  <div class="media-dialog-actions">
  <media-dialog-close class="media-button media-dialog-close">
  </media-dialog-close>
  </div>
  </media-dialog-popup>
  </media-error-dialog>
  <media-controls>
  <media-controls-backdrop class="media-controls__backdrop">
  </media-controls-backdrop>
  <media-controls-content class="media-controls media-controls">
  <media-tooltip-group>
  <media-controls-group class="media-controls-primary">
  <media-play-button class="media-button media-play-button" id="vjs-f7OK7BC5-ev-trigger">
  <span class="contents theme-minimal:hidden">
  <media-icon name="restart" class="media-button-icon media-play-button-restart-icon">
  </media-icon>
  </span>
  <span class="hidden theme-minimal:contents">
  <media-icon family="minimal" name="restart" class="media-button-icon media-play-button-restart-icon">
  </media-icon>
  </span>
  <span class="contents theme-minimal:hidden">
  <media-icon name="play" class="media-button-icon media-play-button-play-icon">
  </media-icon>
  </span>
  <span class="hidden theme-minimal:contents">
  <media-icon family="minimal" name="play" class="media-button-icon media-play-button-play-icon">
  </media-icon>
  </span>
  <span class="contents theme-minimal:hidden">
  <media-icon name="pause" class="media-button-icon media-play-button-pause-icon">
  </media-icon>
  </span>
  <span class="hidden theme-minimal:contents">
  <media-icon family="minimal" name="pause" class="media-button-icon media-play-button-pause-icon">
  </media-icon>
  </span>
  </media-play-button>
  <media-tooltip trigger="vjs-f7OK7BC5-ev-trigger" side="top" class="media-tooltip">
  <media-tooltip-label>
  </media-tooltip-label>
  <media-tooltip-shortcut class="media-tooltip-shortcut">
  </media-tooltip-shortcut>
  </media-tooltip>
  <media-mute-button class="media-button media-mute-button media-controls-volume-button" commandfor="vjs-eEbK5-VC-q1-popup" id="vjs-f7OK7BC5-ev-2-trigger">
  <span class="contents theme-minimal:hidden">
  <media-icon name="volume-off" class="media-button-icon media-mute-button-off-icon">
  </media-icon>
  </span>
  <span class="hidden theme-minimal:contents">
  <media-icon family="minimal" name="volume-off" class="media-button-icon media-mute-button-off-icon">
  </media-icon>
  </span>
  <span class="contents theme-minimal:hidden">
  <media-icon name="volume-low" class="media-button-icon media-mute-button-low-icon">
  </media-icon>
  </span>
  <span class="hidden theme-minimal:contents">
  <media-icon family="minimal" name="volume-low" class="media-button-icon media-mute-button-low-icon">
  </media-icon>
  </span>
  <span class="contents theme-minimal:hidden">
  <media-icon name="volume-high" class="media-button-icon media-mute-button-high-icon">
  </media-icon>
  </span>
  <span class="hidden theme-minimal:contents">
  <media-icon family="minimal" name="volume-high" class="media-button-icon media-mute-button-high-icon">
  </media-icon>
  </span>
  </media-mute-button>
  <media-tooltip trigger="vjs-f7OK7BC5-ev-2-trigger" delay="0" disabled sticky side="top" class="media-tooltip">
  <media-tooltip-label>
  </media-tooltip-label>
  <media-tooltip-shortcut class="media-tooltip-shortcut">
  </media-tooltip-shortcut>
  </media-tooltip>
  <media-volume-popover open-on-hover delay="200" close-delay="100" side="top" class="media-volume-popover" id="vjs-eEbK5-VC-q1-popup">
  <media-volume-slider class="media-slider media-volume-slider" thumb-alignment="edge" orientation="vertical">
  <media-slider-track class="media-slider-track">
  <media-slider-fill class="media-slider-fill">
  </media-slider-fill>
  </media-slider-track>
  <media-slider-thumb class="media-slider-thumb media-volume-slider-thumb">
  </media-slider-thumb>
  </media-volume-slider>
  </media-volume-popover>
  <media-controls-group class="media-time-slider-group">
  <media-time class="media-time-current-value" type="current">
  </media-time>
  <media-time-slider class="media-slider media-time-slider">
  <media-time-slider-chapters class="media-time-slider-chapters">
  <template>
  <div class="media-time-slider-chapter">
  <media-slider-track class="media-slider-track media-time-slider-chapter-track">
  <media-slider-buffer class="media-slider-buffer">
  </media-slider-buffer>
  <media-slider-fill class="media-slider-fill">
  </media-slider-fill>
  </media-slider-track>
  </div>
  </template>
  </media-time-slider-chapters>
  <media-slider-thumb class="media-slider-thumb media-time-slider-thumb">
  </media-slider-thumb>
  <media-slider-preview class="media-slider-preview" overflow="visible">
  <div class="media-slider-thumbnail">
  <media-slider-thumbnail class="media-slider-thumbnail-image">
  </media-slider-thumbnail>
  <span class="contents theme-minimal:hidden">
  <media-icon name="spinner" class="media-slider-thumbnail-spinner-icon">
  </media-icon>
  </span>
  <span class="hidden theme-minimal:contents">
  <media-icon family="minimal" name="spinner" class="media-slider-thumbnail-spinner-icon">
  </media-icon>
  </span>
  </div>
  <div class="media-time-slider-preview-content">
  <media-time-slider-chapter-title class="media-time-slider-chapter-title">
  </media-time-slider-chapter-title>
  <media-slider-value class="media-time-slider-value" type="pointer">
  </media-slider-value>
  </div>
  </media-slider-preview>
  </media-time-slider>
  <media-time class="media-time-remaining-value" type="remaining" toggle>
  </media-time>
  </media-controls-group>
  <media-captions-button class="media-button media-captions-button media-controls-captions-button" id="vjs-f7OK7BC5-ev-3-trigger">
  <span class="contents theme-minimal:hidden">
  <media-icon name="captions-off" class="media-button-icon media-captions-button-off-icon">
  </media-icon>
  </span>
  <span class="hidden theme-minimal:contents">
  <media-icon family="minimal" name="captions-off" class="media-button-icon media-captions-button-off-icon">
  </media-icon>
  </span>
  <span class="contents theme-minimal:hidden">
  <media-icon name="captions-on" class="media-button-icon media-captions-button-on-icon">
  </media-icon>
  </span>
  <span class="hidden theme-minimal:contents">
  <media-icon family="minimal" name="captions-on" class="media-button-icon media-captions-button-on-icon">
  </media-icon>
  </span>
  </media-captions-button>
  <media-tooltip trigger="vjs-f7OK7BC5-ev-3-trigger" side="top" class="media-tooltip">
  <media-tooltip-label>
  </media-tooltip-label>
  <media-tooltip-shortcut class="media-tooltip-shortcut">
  </media-tooltip-shortcut>
  </media-tooltip>
  <button commandfor="vjs--E09Qb0r-t2-popup" class="media-button media-settings-menu-trigger" id="vjs-f7OK7BC5-ev-4-trigger">
  <span class="contents theme-minimal:hidden">
  <media-icon name="gear" class="media-button-icon media-settings-menu-trigger-icon">
  </media-icon>
  </span>
  <span class="hidden theme-minimal:contents">
  <media-icon family="minimal" name="gear" class="media-button-icon media-settings-menu-trigger-icon">
  </media-icon>
  </span>
  <media-text class="media-settings-menu-trigger-label" token="menu.settings">Settings</media-text>
  </button>
  <media-tooltip trigger="vjs-f7OK7BC5-ev-4-trigger" side="top" class="media-tooltip">
  <media-text token="menu.settings">Settings</media-text>
  </media-tooltip>
  <media-menu side="top" align="center" class="media-menu-popup media-controls-settings-button" id="vjs--E09Qb0r-t2-popup">
  <media-menu-content class="media-menu-content">
  <media-menu-item commandfor="vjs-bOPjz1Ka-qh-content" class="media-menu-trigger-item">
  <span class="contents theme-minimal:hidden">
  <media-icon name="switches" class="media-menu-trigger-item-icon">
  </media-icon>
  </span>
  <span class="hidden theme-minimal:contents">
  <media-icon family="minimal" name="switches" class="media-menu-trigger-item-icon">
  </media-icon>
  </span>
  <media-text token="menu.quality">Quality</media-text>
  <span class="media-menu-hint">
  <span data-part="value" class="media-menu-hint-label">
  </span>
  <span class="contents theme-minimal:hidden">
  <media-icon name="chevron" class="media-menu-forward-chevron">
  </media-icon>
  </span>
  <span class="hidden theme-minimal:contents">
  <media-icon family="minimal" name="chevron" class="media-menu-forward-chevron">
  </media-icon>
  </span>
  </span>
  </media-menu-item>
  <media-menu-content class="media-menu-content" id="vjs-bOPjz1Ka-qh-content">
  <media-menu-item class="media-menu-back-item">
  <span class="contents theme-minimal:hidden">
  <media-icon name="chevron" class="media-menu-back-chevron">
  </media-icon>
  </span>
  <span class="hidden theme-minimal:contents">
  <media-icon family="minimal" name="chevron" class="media-menu-back-chevron">
  </media-icon>
  </span>
  <media-text token="menu.quality">Quality</media-text>
  </media-menu-item>
  <media-menu-separator class="media-menu-separator">
  </media-menu-separator>
  <media-quality-radio-group class="media-menu-radio-group">
  <template>
  <media-menu-radio-item class="media-menu-radio-item">
  <span>
  <span data-part="label">
  </span>
  <sup data-part="tier" class="media-menu-tier">
  </sup>
  </span>
  <span data-part="badge" class="media-menu-badge">
  </span>
  <media-menu-item-indicator force-mount class="media-menu-item-indicator">
  <span class="contents theme-minimal:hidden">
  <media-icon name="check" class="media-menu-radio-item-icon">
  </media-icon>
  </span>
  <span class="hidden theme-minimal:contents">
  <media-icon family="minimal" name="check" class="media-menu-radio-item-icon">
  </media-icon>
  </span>
  </media-menu-item-indicator>
  </media-menu-radio-item>
  </template>
  </media-quality-radio-group>
  </media-menu-content>
  <media-menu-item commandfor="vjs-DPaa0Ln5-q8-content" class="media-menu-trigger-item">
  <span class="contents theme-minimal:hidden">
  <media-icon name="speech" class="media-menu-trigger-item-icon">
  </media-icon>
  </span>
  <span class="hidden theme-minimal:contents">
  <media-icon family="minimal" name="speech" class="media-menu-trigger-item-icon">
  </media-icon>
  </span>
  <media-text token="menu.audio">Audio</media-text>
  <span class="media-menu-hint">
  <span data-part="value" class="media-menu-hint-label">
  </span>
  <span class="contents theme-minimal:hidden">
  <media-icon name="chevron" class="media-menu-forward-chevron">
  </media-icon>
  </span>
  <span class="hidden theme-minimal:contents">
  <media-icon family="minimal" name="chevron" class="media-menu-forward-chevron">
  </media-icon>
  </span>
  </span>
  </media-menu-item>
  <media-menu-content class="media-menu-content" id="vjs-DPaa0Ln5-q8-content">
  <media-menu-item class="media-menu-back-item">
  <span class="contents theme-minimal:hidden">
  <media-icon name="chevron" class="media-menu-back-chevron">
  </media-icon>
  </span>
  <span class="hidden theme-minimal:contents">
  <media-icon family="minimal" name="chevron" class="media-menu-back-chevron">
  </media-icon>
  </span>
  <media-text token="menu.audio">Audio</media-text>
  </media-menu-item>
  <media-menu-separator class="media-menu-separator">
  </media-menu-separator>
  <media-audio-track-radio-group class="media-menu-radio-group">
  <template>
  <media-menu-radio-item class="media-menu-radio-item">
  <span data-part="label">
  </span>
  <media-menu-item-indicator force-mount class="media-menu-item-indicator">
  <span class="contents theme-minimal:hidden">
  <media-icon name="check" class="media-menu-radio-item-icon">
  </media-icon>
  </span>
  <span class="hidden theme-minimal:contents">
  <media-icon family="minimal" name="check" class="media-menu-radio-item-icon">
  </media-icon>
  </span>
  </media-menu-item-indicator>
  </media-menu-radio-item>
  </template>
  </media-audio-track-radio-group>
  </media-menu-content>
  <media-menu-item commandfor="vjs-mT1s8PiA-qf-content" class="media-menu-trigger-item">
  <span class="contents theme-minimal:hidden">
  <media-icon name="speed" class="media-menu-trigger-item-icon">
  </media-icon>
  </span>
  <span class="hidden theme-minimal:contents">
  <media-icon family="minimal" name="speed" class="media-menu-trigger-item-icon">
  </media-icon>
  </span>
  <media-text token="menu.speed">Speed</media-text>
  <span class="media-menu-hint">
  <span data-part="value" class="media-menu-hint-label">
  </span>
  <span class="contents theme-minimal:hidden">
  <media-icon name="chevron" class="media-menu-forward-chevron">
  </media-icon>
  </span>
  <span class="hidden theme-minimal:contents">
  <media-icon family="minimal" name="chevron" class="media-menu-forward-chevron">
  </media-icon>
  </span>
  </span>
  </media-menu-item>
  <media-menu-content class="media-menu-content" id="vjs-mT1s8PiA-qf-content">
  <media-menu-item class="media-menu-back-item">
  <span class="contents theme-minimal:hidden">
  <media-icon name="chevron" class="media-menu-back-chevron">
  </media-icon>
  </span>
  <span class="hidden theme-minimal:contents">
  <media-icon family="minimal" name="chevron" class="media-menu-back-chevron">
  </media-icon>
  </span>
  <media-text token="menu.speed">Speed</media-text>
  </media-menu-item>
  <media-menu-separator class="media-menu-separator">
  </media-menu-separator>
  <media-playback-rate-radio-group class="media-menu-radio-group">
  <template>
  <media-menu-radio-item class="media-menu-radio-item">
  <span data-part="label">
  </span>
  <media-menu-item-indicator force-mount class="media-menu-item-indicator">
  <span class="contents theme-minimal:hidden">
  <media-icon name="check" class="media-menu-radio-item-icon">
  </media-icon>
  </span>
  <span class="hidden theme-minimal:contents">
  <media-icon family="minimal" name="check" class="media-menu-radio-item-icon">
  </media-icon>
  </span>
  </media-menu-item-indicator>
  </media-menu-radio-item>
  </template>
  </media-playback-rate-radio-group>
  </media-menu-content>
  <media-menu-item commandfor="vjs-YTqj-PjJ-rk-content" class="media-menu-trigger-item">
  <span class="contents theme-minimal:hidden">
  <media-icon name="captions-off" class="media-menu-trigger-item-icon">
  </media-icon>
  </span>
  <span class="hidden theme-minimal:contents">
  <media-icon family="minimal" name="captions-off" class="media-menu-trigger-item-icon">
  </media-icon>
  </span>
  <media-text token="menu.captions">Captions</media-text>
  <span class="media-menu-hint">
  <span data-part="value" class="media-menu-hint-label">
  </span>
  <span class="contents theme-minimal:hidden">
  <media-icon name="chevron" class="media-menu-forward-chevron">
  </media-icon>
  </span>
  <span class="hidden theme-minimal:contents">
  <media-icon family="minimal" name="chevron" class="media-menu-forward-chevron">
  </media-icon>
  </span>
  </span>
  </media-menu-item>
  <media-menu-content class="media-menu-content" id="vjs-YTqj-PjJ-rk-content">
  <media-menu-item class="media-menu-back-item">
  <span class="contents theme-minimal:hidden">
  <media-icon name="chevron" class="media-menu-back-chevron">
  </media-icon>
  </span>
  <span class="hidden theme-minimal:contents">
  <media-icon family="minimal" name="chevron" class="media-menu-back-chevron">
  </media-icon>
  </span>
  <media-text token="menu.captions">Captions</media-text>
  </media-menu-item>
  <media-menu-separator class="media-menu-separator">
  </media-menu-separator>
  <media-captions-radio-group class="media-menu-radio-group">
  <template>
  <media-menu-radio-item class="media-menu-radio-item">
  <span data-part="label">
  </span>
  <media-menu-item-indicator force-mount class="media-menu-item-indicator">
  <span class="contents theme-minimal:hidden">
  <media-icon name="check" class="media-menu-radio-item-icon">
  </media-icon>
  </span>
  <span class="hidden theme-minimal:contents">
  <media-icon family="minimal" name="check" class="media-menu-radio-item-icon">
  </media-icon>
  </span>
  </media-menu-item-indicator>
  </media-menu-radio-item>
  </template>
  </media-captions-radio-group>
  </media-menu-content>
  </media-menu-content>
  </media-menu>
  </media-controls-group>
  <media-controls-group class="media-controls-secondary">
  <media-cast-button class="media-button media-cast-button" id="vjs-f7OK7BC5-ev-5-trigger">
  <span class="contents theme-minimal:hidden">
  <media-icon name="cast-enter" class="media-button-icon media-cast-button-enter-icon">
  </media-icon>
  </span>
  <span class="hidden theme-minimal:contents">
  <media-icon family="minimal" name="cast-enter" class="media-button-icon media-cast-button-enter-icon">
  </media-icon>
  </span>
  <span class="contents theme-minimal:hidden">
  <media-icon name="cast-exit" class="media-button-icon media-cast-button-exit-icon">
  </media-icon>
  </span>
  <span class="hidden theme-minimal:contents">
  <media-icon family="minimal" name="cast-exit" class="media-button-icon media-cast-button-exit-icon">
  </media-icon>
  </span>
  </media-cast-button>
  <media-tooltip trigger="vjs-f7OK7BC5-ev-5-trigger" side="top" class="media-tooltip">
  <media-tooltip-label>
  </media-tooltip-label>
  <media-tooltip-shortcut class="media-tooltip-shortcut">
  </media-tooltip-shortcut>
  </media-tooltip>
  <media-airplay-button class="media-button media-airplay-button" id="vjs-f7OK7BC5-ev-6-trigger">
  <span class="contents theme-minimal:hidden">
  <media-icon name="airplay-enter" class="media-button-icon media-airplay-button-enter-icon">
  </media-icon>
  </span>
  <span class="hidden theme-minimal:contents">
  <media-icon family="minimal" name="airplay-enter" class="media-button-icon media-airplay-button-enter-icon">
  </media-icon>
  </span>
  <span class="contents theme-minimal:hidden">
  <media-icon name="airplay-exit" class="media-button-icon media-airplay-button-exit-icon">
  </media-icon>
  </span>
  <span class="hidden theme-minimal:contents">
  <media-icon family="minimal" name="airplay-exit" class="media-button-icon media-airplay-button-exit-icon">
  </media-icon>
  </span>
  </media-airplay-button>
  <media-tooltip trigger="vjs-f7OK7BC5-ev-6-trigger" side="top" class="media-tooltip">
  <media-tooltip-label>
  </media-tooltip-label>
  <media-tooltip-shortcut class="media-tooltip-shortcut">
  </media-tooltip-shortcut>
  </media-tooltip>
  <media-pip-button class="media-button media-pip-button" id="vjs-f7OK7BC5-ev-7-trigger">
  <span class="contents theme-minimal:hidden">
  <media-icon name="pip-enter" class="media-button-icon media-pip-button-enter-icon">
  </media-icon>
  </span>
  <span class="hidden theme-minimal:contents">
  <media-icon family="minimal" name="pip-enter" class="media-button-icon media-pip-button-enter-icon">
  </media-icon>
  </span>
  <span class="contents theme-minimal:hidden">
  <media-icon name="pip-exit" class="media-button-icon media-pip-button-exit-icon">
  </media-icon>
  </span>
  <span class="hidden theme-minimal:contents">
  <media-icon family="minimal" name="pip-exit" class="media-button-icon media-pip-button-exit-icon">
  </media-icon>
  </span>
  </media-pip-button>
  <media-tooltip trigger="vjs-f7OK7BC5-ev-7-trigger" side="top" class="media-tooltip">
  <media-tooltip-label>
  </media-tooltip-label>
  <media-tooltip-shortcut class="media-tooltip-shortcut">
  </media-tooltip-shortcut>
  </media-tooltip>
  <media-fullscreen-button class="media-button media-fullscreen-button" id="vjs-f7OK7BC5-ev-8-trigger">
  <span class="contents theme-minimal:hidden">
  <media-icon name="fullscreen-enter" class="media-button-icon media-fullscreen-button-enter-icon">
  </media-icon>
  </span>
  <span class="hidden theme-minimal:contents">
  <media-icon family="minimal" name="fullscreen-enter" class="media-button-icon media-fullscreen-button-enter-icon">
  </media-icon>
  </span>
  <span class="contents theme-minimal:hidden">
  <media-icon name="fullscreen-exit" class="media-button-icon media-fullscreen-button-exit-icon">
  </media-icon>
  </span>
  <span class="hidden theme-minimal:contents">
  <media-icon family="minimal" name="fullscreen-exit" class="media-button-icon media-fullscreen-button-exit-icon">
  </media-icon>
  </span>
  </media-fullscreen-button>
  <media-tooltip trigger="vjs-f7OK7BC5-ev-8-trigger" side="top" class="media-tooltip">
  <media-tooltip-label>
  </media-tooltip-label>
  <media-tooltip-shortcut class="media-tooltip-shortcut">
  </media-tooltip-shortcut>
  </media-tooltip>
  </media-controls-group>
  </media-tooltip-group>
  </media-controls-content>
  </media-controls>
  <media-hotkey keys="Space" action="togglePaused">
  </media-hotkey>
  <media-hotkey keys="k" action="togglePaused">
  </media-hotkey>
  <media-hotkey keys="m" action="toggleMuted">
  </media-hotkey>
  <media-hotkey keys="ArrowRight" action="seekStep" value="5">
  </media-hotkey>
  <media-hotkey keys="ArrowLeft" action="seekStep" value="-5">
  </media-hotkey>
  <media-hotkey keys="l" action="seekStep" value="10">
  </media-hotkey>
  <media-hotkey keys="j" action="seekStep" value="-10">
  </media-hotkey>
  <media-hotkey keys="ArrowUp" action="volumeStep" value="0.05">
  </media-hotkey>
  <media-hotkey keys="ArrowDown" action="volumeStep" value="-0.05">
  </media-hotkey>
  <media-hotkey keys="0-9" action="seekToPercent">
  </media-hotkey>
  <media-hotkey keys="Home" action="seekToPercent" value="0">
  </media-hotkey>
  <media-hotkey keys="End" action="seekToPercent" value="100">
  </media-hotkey>
  <media-hotkey keys="&gt;" action="speedUp">
  </media-hotkey>
  <media-hotkey keys="&lt;" action="speedDown">
  </media-hotkey>
  <media-hotkey keys="f" action="toggleFullscreen">
  </media-hotkey>
  <media-hotkey keys="c" action="toggleSubtitles">
  </media-hotkey>
  <media-hotkey keys="i" action="togglePictureInPicture">
  </media-hotkey>
  <media-gesture type="tap" action="togglePaused" pointer="mouse" region="center">
  </media-gesture>
  <media-gesture type="tap" action="toggleControls" pointer="touch">
  </media-gesture>
  <media-gesture type="doubletap" action="seekStep" value="-10" region="left">
  </media-gesture>
  <media-gesture type="doubletap" action="toggleFullscreen" region="center">
  </media-gesture>
  <media-gesture type="doubletap" action="seekStep" value="10" region="right">
  </media-gesture>
  <media-status-announcer class="media-status-announcer">
  </media-status-announcer>
  <div class="media-video-status-indicators">
  <media-volume-indicator class="media-volume-indicator">
  <media-volume-indicator-fill class="media-volume-indicator-fill">
  <span class="contents theme-minimal:hidden">
  <media-icon name="volume-high" class="media-volume-indicator-high-icon">
  </media-icon>
  </span>
  <span class="hidden theme-minimal:contents">
  <media-icon family="minimal" name="volume-high" class="media-volume-indicator-high-icon">
  </media-icon>
  </span>
  <span class="contents theme-minimal:hidden">
  <media-icon name="volume-low" class="media-volume-indicator-low-icon">
  </media-icon>
  </span>
  <span class="hidden theme-minimal:contents">
  <media-icon family="minimal" name="volume-low" class="media-volume-indicator-low-icon">
  </media-icon>
  </span>
  <span class="contents theme-minimal:hidden">
  <media-icon name="volume-off" class="media-volume-indicator-off-icon">
  </media-icon>
  </span>
  <span class="hidden theme-minimal:contents">
  <media-icon family="minimal" name="volume-off" class="media-volume-indicator-off-icon">
  </media-icon>
  </span>
  <media-volume-indicator-value class="media-volume-indicator-value">
  </media-volume-indicator-value>
  </media-volume-indicator-fill>
  </media-volume-indicator>
  <media-status-indicator actions="toggleSubtitles,toggleFullscreen,togglePictureInPicture" class="media-status-indicator">
  <div class="media-status-indicator-content">
  <span class="contents theme-minimal:hidden">
  <media-icon name="captions-on" class="media-status-indicator-captions-on-icon">
  </media-icon>
  </span>
  <span class="hidden theme-minimal:contents">
  <media-icon family="minimal" name="captions-on" class="media-status-indicator-captions-on-icon">
  </media-icon>
  </span>
  <span class="contents theme-minimal:hidden">
  <media-icon name="captions-off" class="media-status-indicator-captions-off-icon">
  </media-icon>
  </span>
  <span class="hidden theme-minimal:contents">
  <media-icon family="minimal" name="captions-off" class="media-status-indicator-captions-off-icon">
  </media-icon>
  </span>
  <span class="contents theme-minimal:hidden">
  <media-icon name="fullscreen-enter" class="media-status-indicator-fullscreen-enter-icon">
  </media-icon>
  </span>
  <span class="hidden theme-minimal:contents">
  <media-icon family="minimal" name="fullscreen-enter" class="media-status-indicator-fullscreen-enter-icon">
  </media-icon>
  </span>
  <span class="contents theme-minimal:hidden">
  <media-icon name="fullscreen-exit" class="media-status-indicator-fullscreen-exit-icon">
  </media-icon>
  </span>
  <span class="hidden theme-minimal:contents">
  <media-icon family="minimal" name="fullscreen-exit" class="media-status-indicator-fullscreen-exit-icon">
  </media-icon>
  </span>
  <span class="contents theme-minimal:hidden">
  <media-icon name="pip-enter" class="media-status-indicator-pip-enter-icon">
  </media-icon>
  </span>
  <span class="hidden theme-minimal:contents">
  <media-icon family="minimal" name="pip-enter" class="media-status-indicator-pip-enter-icon">
  </media-icon>
  </span>
  <span class="contents theme-minimal:hidden">
  <media-icon name="pip-exit" class="media-status-indicator-pip-exit-icon">
  </media-icon>
  </span>
  <span class="hidden theme-minimal:contents">
  <media-icon family="minimal" name="pip-exit" class="media-status-indicator-pip-exit-icon">
  </media-icon>
  </span>
  <media-status-indicator-value class="media-status-indicator-value">
  </media-status-indicator-value>
  </div>
  </media-status-indicator>
  <media-seek-indicator class="media-seek-indicator">
  <span class="contents theme-minimal:hidden">
  <media-icon name="chevron" class="media-seek-indicator-icon">
  </media-icon>
  </span>
  <span class="hidden theme-minimal:contents">
  <media-icon family="minimal" name="chevron" class="media-seek-indicator-icon">
  </media-icon>
  </span>
  <media-seek-indicator-value class="media-seek-indicator-value">
  </media-seek-indicator-value>
  </media-seek-indicator>
  <media-status-indicator actions="togglePaused" class="media-playback-status-indicator">
  <span class="contents theme-minimal:hidden">
  <media-icon name="play" class="media-playback-status-indicator-play-icon">
  </media-icon>
  </span>
  <span class="hidden theme-minimal:contents">
  <media-icon family="minimal" name="play" class="media-playback-status-indicator-play-icon">
  </media-icon>
  </span>
  <span class="contents theme-minimal:hidden">
  <media-icon name="pause" class="media-playback-status-indicator-pause-icon">
  </media-icon>
  </span>
  <span class="hidden theme-minimal:contents">
  <media-icon family="minimal" name="pause" class="media-playback-status-indicator-pause-icon">
  </media-icon>
  </span>
  </media-status-indicator>
  </div>
  </media-container>
</video-player>

Skins, features, and presets

Each skin is built with specific features in mind. For example, a video skin renders fullscreen and picture-in-picture controls. An audio skin doesn’t.

You’ll find a preconfigured player, its typed hook, a skin, and the matching feature bundle exported from the same path. We call these paths presets.

ImportDescriptionDetails
@videojs/html/videoGeneral-purpose video player preset with full playback controls.
@videojs/html/audioAudio-only player preset with playback and volume controls.
@videojs/html/backgroundAmbient background video preset with no user controls.
@videojs/html/live-audioLive audio player preset — audio minus playback rate, plus the live feature, with a skin that swaps the time slider and time displays for a Live button.
@videojs/html/live-videoLive video player preset — video minus playback rate, quality selection, and audio-track selection, plus the live feature, with a skin that swaps the time slider and time displays for a Live button.

Styling

Packaged skins use vanilla CSS. Their documented CSS custom properties cover common visual changes.

The skin registration entry point imports its styles automatically.

Either way the styles travel inside the skin’s JavaScript and apply when the element upgrades, so there is no stylesheet to add. The CDN publishes them as files as well, which matters when you want the player’s box styled before that upgrade — see Self-host the player.

To use Tailwind or change the underlying CSS, eject the skin and edit its styles in your app.

Shared limitations

  • Skin spacing and icons use a fixed 16px base by default. Vanilla CSS font sizes use the same base, while Tailwind font sizes use rem units and assume a 16px root font size.
  • The default font stack includes Inter, but we do not load the webfont for you. If Inter is unavailable, the skin uses system fonts.

Ejected vanilla CSS

  • We use a BEM classname structure and every component classname is scoped with a media- prefix.

Ejected Tailwind

  • Ejected skins establish their own spacing scale but otherwise assume the default configuration. A future CLI eject command will support custom class prefixes. For now, edit the ejected skin to use your prefix.
  • Ejected skins currently support Tailwind 4.3.x.