# Poster

Poster image component that displays a thumbnail until video playback starts

## Import

```tsx
import { Poster } from '@videojs/react';
```

## Anatomy

```tsx
<Poster.Root>
  <Poster.Image />
</Poster.Root>
```

## 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.

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:

```tsx
<VideoPlayer poster="poster.jpg" />
```

## 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.

`Poster.Root` owns visibility and loading state. Image attributes go on `Poster.Image`:

```tsx
<Poster.Root>
  <Poster.Image srcSet="poster-480.jpg 480w, poster-1080.jpg 1080w" sizes="100vw" />
</Poster.Root>
```

To render a different image component, use `render` on `Poster.Image`. It receives the poster URL as `src`, undefined until one resolves:

```tsx
<Poster.Root>
  <Poster.Image
    render={({ src, ...props }: ComponentProps<'img'>) =>
      src ? <Image {...props} src={src} alt="" fill /> : null
    }
  />
</Poster.Root>
```

Inside a skin, pass the same function as `renderPoster`. The skin draws your image in place of its own:

```tsx
<VideoSkin
  renderPoster={({ src, ...props }: ComponentProps<'img'>) =>
    src ? <Image {...props} src={src} alt="" fill /> : null
  }
/>
```

A skin styles the `<img>` it draws directly. Render something that is not an `<img>` 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.

React renders a root `<div>` around the `<img>`. The state attributes are on `Poster.Root`, so other presentation layers can use the same lifecycle:

```tsx
<Poster.Root className="media-poster">
  <img className="media-poster-blur" src={blurDataURL} alt="" aria-hidden />
  <Poster.Image className="media-poster-image" />
  <div className="media-poster-overlay" aria-hidden />
</Poster.Root>
```

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

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

## 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:

```tsx
<Poster.Root>
  <Poster.Image alt="Keynote speaker at a conference" />
</Poster.Root>
```

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

**App.tsx**

```tsx
import { Container, createPlayer, PlayButton, Poster } from '@videojs/react';
import { Video, videoFeatures } from '@videojs/react/video';

const { Player } = createPlayer({ features: videoFeatures });

export default function BasicUsage() {
  return (
    <Player poster="https://image.mux.com/BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM/thumbnail.jpg">
      <Container className="media-container">
        <Video src="https://stream.mux.com/BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM/highest.mp4" playsInline />

        <Poster.Root className="media-poster">
          <Poster.Image className="media-poster-image" />
        </Poster.Root>

        <PlayButton
          className="media-play-button"
          render={(props, state) => <button {...props}>{state.paused ? 'Play' : 'Pause'}</button>}
        />
      </Container>
    </Player>
  );
}
```

**App.css**

```css
.media-container {
  position: relative;
}

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

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

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

.media-poster-image {
  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);
}
```

## API Reference

### Root

Manages poster visibility and image loading state.

Renders a `div` and exposes `data-visible`, `data-loading`, `data-loaded`, and `data-error` for styling every layer in the poster presentation. Render `Poster.Image` inside it for the image that supplies the loading lifecycle.

#### State

State is accessible via the `render`, `className`, and `style` props.

| 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. |

### Image

Displays the poster image managed by `Poster.Root`.

Renders an `img`, so `srcSet`, `sizes`, `loading`, and the rest of the native image attributes remain available. Leave the source off and the player's resolved poster fills it in. The image is decorative unless you supply `alt`.

#### Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `className` | `string \| ((state: PosterState) => string \| undefined)` | — | Class name or function returning class name from state. |
| `render` | `ReactElement \| ((props: HTMLProps, state: PosterState) => ReactElement \| null)` | — | Render prop for custom element. |
| `style` | `CSSProperties \| ((state: PosterState) => CSSProperties \| undefined)` | — | Style or function returning style from state. |

---

React documentation: https://videojs.org/docs/framework/react/llms.txt
All documentation: https://videojs.org/llms.txt
