Skip to content

GuidePlayback

Add a poster and loading placeholder

Set the image shown before playback, then add a lightweight placeholder while it loads

A poster is the image shown before your video plays. There are several places to set one, so work down this list and stop at the first step that fits:

  1. Let the media provide it. Some media components create a poster from the source, so there is nothing extra to host or keep in sync.
  2. Set poster on the player. With a packaged skin, that is all a static image needs.
  3. Take control of the image when you need a framework image component, a <picture> element, or a loading placeholder. The skin renders your image instead of its own.
  4. Keep it working after adding the skin source to your project. The player’s poster still reaches the Poster component your skin renders. You can also set the image’s source yourself.

Let the media provide a poster

Some media components choose a poster for you. For example, <mux-video> creates one from its playback ID:

Install the HTML façade and the Mux playback adapter:

pnpm add @videojs/html @videojs/mux-video
<video-player>
  <video-skin>
    <mux-video
      src="https://stream.mux.com/BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM.m3u8"
      poster-time="2"
      playsinline
    ></mux-video>
  </video-skin>
</video-player>
<script type="module">
  import '@videojs/html/video/player';
  import '@videojs/html/video/skin';
  import '@videojs/html/media/mux-video';
</script>

Set a poster on the player

When the media has no poster of its own, set the player’s poster to an image URL:

<video-player poster="/poster.jpg">
  <video-skin>
    <video src="/video.mp4" playsinline></video>
  </video-skin>
</video-player>
<script type="module">
  import '@videojs/html/video/player';
  import '@videojs/html/video/skin';
</script>

A packaged skin includes <media-poster> and shows the image automatically. If you build your own UI, add <media-poster> yourself. The poster hides after the user plays or seeks.

When the player and the media component both choose a poster, the player’s poster wins. See Metadata for how the player combines those values.

Set poster on the player to supply the skin’s image. A poster on the native <video> or React Video sets only the browser’s poster; it does not populate the player’s Poster component, renderPoster, or the HTML poster slot.

Posters are decorative by default, with an empty alt. If the image communicates something that is not available elsewhere, add alt text when you customize the poster image.

Take control of the poster image

When a plain <img> is not enough, give the packaged skin an image of your own:

Add your image to the skin’s poster slot. If you leave off src, Video.js fills in the player’s poster. If you provide a src, a srcset, or <picture> sources, Video.js leaves the image alone. Keep the player and skin imports from the previous section:

<video-player>
  <video-skin>
    <video src="/video.mp4" playsinline></video>
    <picture slot="poster">
      <source media="(min-width: 1200px)" srcset="/poster-1080.jpg" />
      <img src="/poster-480.jpg" alt="" />
    </picture>
  </video-skin>
</video-player>
<style>
  video-skin > picture[slot="poster"] > img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: var(--media-object-fit, contain);
    object-position: var(--media-object-position, center);
  }
</style>

Add a loading placeholder

A placeholder is a tiny preview that appears while the poster downloads, so a slow poster does not leave the player as empty space. Keep it small enough to include directly in the page, for example as a short data URL. Add it to the customized image from the previous section.

Replace data:image/webp;base64,… in the examples below with a complete data URL generated from your poster.

Add an image to the poster slot

Add an image to the skin’s poster slot with the placeholder as its background. Leave off src so Video.js can add the poster URL. The background appears immediately, before the poster loads.

<video-player poster="/poster.jpg">
  <video-skin>
    <video src="/video.mp4" playsinline></video>
    <img
      slot="poster"
      alt=""
      style="background: url('data:image/webp;base64,…') var(--media-object-position, center) / contain no-repeat"
    >
  </video-skin>
</video-player>

The examples use contain for both images. Use cover for both when the poster should fill the player. Keeping the same size and position prevents the image from jumping when the poster appears.

Set the poster after adding skin source

After you add the skin source to your project, the first two approaches still work. The player’s poster, or the poster the media provides, reaches the <media-poster> element your skin renders.

<media-poster> fills the src of the image inside it. If you give that image a src, a srcset, or <picture> sources, Video.js leaves it untouched. Set the source here when the poster should bypass player state entirely.

Keep your skin’s existing classes and put the background on the image inside <media-poster>:

<media-poster class="media-poster">
  <img
    class="media-poster-image"
    alt=""
    style="background: url('data:image/webp;base64,…') var(--media-object-position, center) / contain no-repeat"
  >
</media-poster>

Troubleshooting

No poster appears

Check that the player has a poster or that the media component can create one from its source.

A poster set only on the native media element does not reach the skin’s Poster. Move that URL to the player’s poster.

The final poster never appears

To let Video.js add the poster URL, leave off src, srcset, and any parent <picture> sources. If you provide any of them, Video.js leaves the image unchanged.

The placeholder and poster use different crops

Use the same fit for both images: pair background-size: contain with object-fit: contain, or use cover for both.

The placeholder adds too much page weight

Use fewer pixels and stronger compression. The placeholder only needs to suggest the poster’s color and shape until the full image appears.

Components

API

Guides