# 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](./customize-skins.md#style-skin-source).** The player’s `poster` still reaches the Poster component your skin renders, or you can 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:

```bash
pnpm add @videojs/html @videojs/mux-video
```

```html
<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:

```html
<video-player poster="/poster.jpg">
  <video-skin>
    <video src="/video.mp4" playsinline></video>
  </video-skin>
</video-player>
```

If you use a ready-made skin, it includes [`<media-poster>`](../reference/components/poster.md) and shows the image automatically. If you build your own UI, add `<media-poster>` yourself. It 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](../reference/api/feature-metadata.md) for how the player combines those values.

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

The packaged skins also accept an image of your own, for when a plain `<img>` is not enough:

Add your image to the skin’s `poster` slot. Leave off `src` and Video.js fills in the player’s poster. Provide a `src`, a `srcset`, or `<picture>` sources and Video.js leaves the image alone:

```html
<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>
```

## 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 with the page, such as a short data URL. Add it to the customized image from the previous section.

### 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`: Video.js adds the poster URL, while the background appears immediately.

```html
<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

Adding the skin source to your project changes nothing about the first two approaches: the player’s `poster`, or the poster the media provides, still reaches the [`<media-poster>`](../reference/components/poster.md) element your skin renders.

`<media-poster>` fills the `src` of the image inside it. Give that image a `src`, a `srcset`, or `<picture>` sources instead and Video.js leaves it untouched — set the source at this level when the poster should bypass player state entirely.

For a placeholder, put the background on the image inside `<media-poster>`:

```html
<media-poster>
  <img
    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.

### The final poster never appears

Leave off `src`, `srcset`, and any parent `<picture>` sources when you want Video.js to add the poster URL. If you provide one of those values, Video.js leaves it 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.

## Related pages

### Components

- [media-poster](../reference/components/poster.md): Poster image component that displays a thumbnail until video playback starts

### API

- [Metadata](../reference/api/feature-metadata.md): Resolved title and poster values for the player store

### Guides

- [Customize skins](./customize-skins.md#style-a-packaged-skin): Style a packaged Video.js skin or add its source to change controls, layout, styles, and interactions
- [Build your own UI component](./build-your-own-component.md): Create custom player controls that read state, dispatch actions, and stay accessible.