# media-poster

Poster image component that displays a thumbnail until video playback starts

## Import

```ts
import '@videojs/html/ui/poster';
```

## Anatomy

```html
<media-poster>
  <img alt="" />
</media-poster>
```

## Behavior

The poster shows before playback starts. Once the user plays or seeks, it hides; pausing does not bring it back. Loading a new source shows it again.

The `<img>` child is optional. Leave it out and `<media-poster>` draws one of its own in its shadow DOM.

You can set the poster URL on the player. This is useful when you want to change the poster from inside a skin, or keep all your media metadata in one place:

```html
<video-player poster="poster.jpg"></video-player>
```

## Supply your own image

The component fills in a source only when you leave one out. `srcset`, `sizes`, `loading`, `<picture>`, and framework image components all stay available.

`<media-poster>` draws a fallback image in its shadow DOM and fills in its `src`. Put an `<img>` inside it and the element uses yours instead, filling in its `src` the same way:

```html
<media-poster>
  <img alt="" />
</media-poster>
```

Give that image a `src`, a `srcset`, or `<source>` candidates and it is yours; the component leaves it alone:

```html
<media-poster>
  <img src="poster.jpg" srcset="poster-480.jpg 480w, poster-1080.jpg 1080w" alt="Keynote speaker" />
</media-poster>
```

Inside a skin, slot your image instead. The skin carries a plain one that yours replaces:

```html
<video-skin>
  <video src="video.mp4" playsinline></video>
  <img slot="poster" src="poster.jpg" alt="Keynote speaker" />
</video-skin>
```

A skin can only style an `<img>` you slot directly. Wrap one in a `<picture>` or a framework component and its sizing is yours.

## Styling

| Attribute | Values | Description |
| --- | --- | --- |
| `data-visible` | Present / absent | Present before playback starts |
| `data-loading` | Present / absent | Present while the image is fetching |
| `data-loaded` | Present / absent | Present once the image has loaded |
| `data-error` | Present / absent | Present when the image failed |

The three load attributes track the image on screen, including one you supplied yourself.

```css
media-poster:not([data-visible]) {
  opacity: 0;
}
```

The image the element draws is exposed as a part. An image you supply is an ordinary child, so style it as a descendant:

```css
media-poster::part(image),
media-poster img {
  object-fit: cover;
}
```

From inside a skin’s shadow root, an image slotted from outside needs `::slotted(img)` as well.

## Accessibility

Unlike the native `<video poster>` attribute, this component lets you describe the poster for screen readers.

The image is decorative by default (`alt=""`), since a URL says nothing about what the image shows. When the poster carries meaning, say so:

```html
<media-poster>
  <img src="poster.jpg" alt="Keynote speaker at a conference" />
</media-poster>
```

Whether a poster is informative or decorative is your judgment, per the [WAI guidelines](https://www.w3.org/WAI/tutorials/images/decorative/).

## Examples

### Basic Usage

**index.html**

```html
<!-- TODO: add a captions track to the demo. -->
<video-player class="video-player" poster="https://image.mux.com/BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM/thumbnail.jpg">
  <media-container>
    <video src="https://stream.mux.com/BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM/highest.mp4" playsinline></video>

    <media-poster class="media-poster">
      <img alt="" />
    </media-poster>

    <media-play-button class="media-play-button">
      <span class="paused">Play</span>
      <span class="playing">Pause</span>
    </media-play-button>
  </media-container>
</video-player>
```

**index.css**

```css
.video-player media-container {
  position: relative;
  display: block;
}

.video-player media-container video {
  width: 100%;
}

.media-poster {
  position: absolute;
  inset: 0;
  pointer-events: none;
  transition: opacity 0.25s;
}

.media-poster:not([data-visible]) {
  opacity: 0;
}

.media-poster img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.media-play-button {
  position: absolute;
  bottom: 10px;
  left: 10px;
  padding-block: 8px;
  padding-inline: 16px;
  color: black;
  cursor: pointer;
  background: rgba(255, 255, 255, 0.75);
  border: 1px solid rgba(255, 255, 255, 0.25);
  border-radius: 9999px;
  backdrop-filter: blur(10px);
}

.media-play-button .paused,
.media-play-button .playing {
  display: none;
}

.media-play-button[data-paused] .paused {
  display: inline;
}

.media-play-button:not([data-paused]) .playing {
  display: inline;
}
```

**index.ts**

```ts
import '@videojs/html/video/player';
import '@videojs/html/ui/container';
import '@videojs/html/ui/play-button';
import '@videojs/html/ui/poster';
```

## API Reference

### media-poster

`<media-poster>` — sets `src` on a poster image it does not own.

The image is a child, as in `<picture>`, but sourcing runs the other way around: `<picture>` treats the `src` on its `<img>` as the fallback, while here an image with no source of its own is the one this element fills in. Give the child a `src`, a `srcset`, or `<source>` candidates and it is yours, left alone.

Left empty, the element draws an image of its own in its shadow root. Supply one as a child to describe it or wrap it: `<media-poster><img alt="Keynote speaker"></media-poster>`. Inside a skin, an `<img slot="poster">` of yours replaces the one the skin carries.

#### State

State is reflected as data attributes for CSS styling.

| Property | Type | Description |
| --- | --- | --- |
| `visible` | `boolean` | Whether the poster should be shown, which it is until playback starts. |
| `src` | `string` | Resolved poster URL, empty when nothing supplied one. |
| `loading` | `boolean` | Whether the poster image is fetching. |
| `loaded` | `boolean` | Whether the poster image has decoded. |
| `error` | `boolean` | Whether the poster image failed. |

#### Data attributes

| Attribute | Description |
| --- | --- |
| `data-visible` | Present until playback starts. |
| `data-loading` | Present while the poster image is fetching. |
| `data-loaded` | Present once the poster image has decoded. |
| `data-error` | Present when the poster image failed. |

---

HTML documentation: https://videojs.org/docs/framework/html/llms.txt
All documentation: https://videojs.org/llms.txt
