# youtube-video

Video component that plays YouTube videos and playlists through the YouTube IFrame player

The [YouTube IFrame player](https://developers.google.com/youtube/iframe_api_reference) keeps its own chrome hidden by default, so it drops into a [player skin](https://videojs.org/docs/framework/html/guides/skins) like any other media component; set `controls` to use YouTube’s UI instead.

## Import

```bash
pnpm add @videojs/youtube-video
```

```ts
import '@videojs/html/media/youtube-video';
```

Or load it from the [CDN](https://videojs.org/docs/framework/html/guides/cdn):

```html
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.0.0-rc.4/media/youtube-video.js"></script>
```

## Load a source

`src` takes a YouTube URL or a raw 11-character video id. Watch, share (`youtu.be`), embed, Shorts, live, and privacy-enhanced (`youtube-nocookie.com`) URLs all work. Playlist URLs load through their `list` parameter, and a `t` parameter sets the start position.

```html
<youtube-video src="https://www.youtube.com/watch?v=aqz-KE-bpKQ"></youtube-video>
```

## Behavior

A few things work differently from a native `<video>` element, because the IFrame API doesn’t expose them:

- `loop` restarts playback when the video ends; the IFrame API has no single-video loop.
- Fullscreen targets the iframe, so YouTube’s own chrome shows in fullscreen.
- Picture-in-picture is unavailable, and the player reports it as unsupported.
- Caption tracks appear in `textTracks` once playback starts; YouTube reports no caption metadata before then.

## Examples

### Basic Usage

**index.html**

```html
<youtube-video class="youtube-video" src="https://www.youtube.com/watch?v=aqz-KE-bpKQ" controls></youtube-video>
```

**index.css**

```css
.youtube-video {
  width: 100%;
  aspect-ratio: 16 / 9;
}
```

**index.ts**

```ts
import '@videojs/html/media/youtube-video';
```

## API Reference

### Attributes

These attributes configure the embedded media adapter:

| Attribute | Type | Default |
| --- | --- | --- |
| `autoplay` | `boolean` | `false` |
| `controls` | `boolean` | `false` |
| `loop` | `boolean` | `false` |
| `muted` | `boolean` | `false` |
| `playsinline` | `boolean` | `true` |
| `poster` | `string` | `''` |
| `preload` | `MediaPreloadType` | `'metadata'` |
| `src` | `string` | `''` |

### Properties

| Property | Type | Default | Description |
| --- | --- | --- | --- |
| `autoplay` | `boolean` | `false` | |
| `buffered` | `TimeRangeLike` | — | Read-only. |
| `controls` | `boolean` | `false` | |
| `currentSrc` | `string` | — | Read-only. |
| `currentTime` | `number` | — | |
| `defaultMuted` | `boolean` | `false` | |
| `duration` | `number` | — | Read-only. |
| `ended` | `boolean` | — | Read-only. |
| `engine` | `{ playVideo(): void; pauseVideo(): void; seekTo(seconds: number, allowSeekAhead: boolean): void; mute(): void; unMute(): void; isMuted(): boolean; setVolume(volume: number): void; getVolume(): number; getDuration(): number; getCurrentTime(): number; getPlaybackRate(): number; setPlaybackRate(rate: number): void; getVideoLoadedFraction(): number; getPlayerState(): number; loadVideoById(options: { videoId: string; startSeconds?: number }): void; cueVideoById(options: { videoId: string; startSeconds?: number }): void; loadPlaylist(options: { list: string; listType?: string }): void; cuePlaylist(options: { list: string; listType?: string }): void; stopVideo(): void; getOption(module: string, option: string): unknown; setOption(module: string, option: string, value: unknown): void; addEventListener(type: string, listener: ((event: { data: number }) => void)): void; destroy(): void } \| null` | — | Read-only. Underlying YouTube iframe API player instance (null until the API loads). |
| `error` | `MediaError \| null` | — | Read-only. |
| `isFullscreen` | `boolean` | — | Read-only. |
| `loop` | `boolean` | `false` | |
| `muted` | `boolean` | `false` | |
| `paused` | `boolean` | — | Read-only. |
| `playbackRate` | `number` | — | |
| `played` | `{ length: number; start(index: number): number; end(index: number): number }` | — | Read-only. |
| `playsInline` | `boolean` | `true` | |
| `poster` | `string` | `''` | |
| `preload` | `MediaPreloadType` | `'metadata'` | |
| `readyState` | `number` | — | Read-only. |
| `seekable` | `TimeRangeLike` | — | Read-only. |
| `seeking` | `boolean` | — | Read-only. |
| `source` | `{ src?: string; engine?: YouTubeSourceEngineConfig } \| null` | `null` | YouTube URL or id in `src`, plus player parameters under `engine.youtube`. Replacing it re-derives `src`. |
| `src` | `string` | `''` | |
| `textTracks` | `TextTrackListLike` | — | Read-only. |
| `volume` | `number` | — | |

### Engine options

#### `source.engine.youtube`

Pass [YouTube player parameters](https://developers.google.com/youtube/player_parameters) under `source.engine.youtube`, spelled exactly as YouTube spells them. They’re serialized onto the embed URL untouched, and the embed reads them once, when its URL is built. [Media Sources](https://videojs.org/docs/framework/html/guides/media-sources) covers how engine options fit into a structured source.

`autoplay`, `controls`, and `playsinline` come from the props of the same name, so they have no `engine.youtube` spelling. Parameters YouTube has deprecated are absent as well: `modestbranding`, `showinfo`, `autohide`, `theme`, and `listType: 'search'`. Anything YouTube adds next passes through the same way.

```ts
const video = document.querySelector('youtube-video');
video.source = {
  src: 'https://www.youtube.com/watch?v=aqz-KE-bpKQ',
  engine: { youtube: { hl: 'de', cc_load_policy: 1 } },
};
```

| Option | Type | Description |
| --- | --- | --- |
| `cc_lang_pref` | `string \| undefined` | ISO 639-1 language to display captions in. Pair with `cc_load_policy`. |
| `cc_load_policy` | `1 \| undefined` | Show closed captions by default, even if the viewer has turned them off. |
| `color` | `'red' \| 'white' \| undefined` | Progress-bar highlight color. Defaults to `'red'`. |
| `disablekb` | `0 \| 1 \| undefined` | Stop responding to keyboard controls. Defaults to `0`. |
| `enablejsapi` | `0 \| 1 \| undefined` | Allow the player to be driven through the IFrame Player API. Defaults to `0`. |
| `end` | `number \| undefined` | Stop playback this many seconds from the start of the video. |
| `fs` | `0 \| 1 \| undefined` | Display the fullscreen button. Defaults to `1`. |
| `hl` | `string \| undefined` | Player interface language: an ISO 639-1 code or full locale (`fr`, `fr-ca`). |
| `iv_load_policy` | `1 \| 3 \| undefined` | Show video annotations (`1`) or hide them (`3`). Defaults to `1`. |
| `list` | `string \| undefined` | Playlist id (prefixed with `PL`) or channel name, depending on `listType`. |
| `listType` | `'playlist' \| 'user_uploads' \| undefined` | What `list` refers to. |
| `loop` | `0 \| 1 \| undefined` | Repeat playback. Looping a single video also needs `playlist` set to the same id. |
| `origin` | `string \| undefined` | Embedding domain. Set it whenever `enablejsapi` is `1`. |
| `playlist` | `string \| undefined` | Comma-separated video ids to play after the one named by the URL path. |
| `referrerPolicy` | `ReferrerPolicy \| undefined` | `referrerpolicy` for the embed iframe. Not a YouTube player parameter. |
| `rel` | `0 \| 1 \| undefined` | Draw related videos from the same channel (`0`) or anywhere (`1`). Defaults to `1`. |
| `start` | `number \| undefined` | Begin playback this many seconds from the start of the video. |
| `widget_referrer` | `string \| undefined` | Embedding URL reported to YouTube Analytics for widget-hosted players. |

### Methods

Supports these media methods: `exitFullscreen`, `load`, `pause`, `play`, `requestFullscreen`.

### Events

Implements these standard media events through the embedded player: `durationchange`, `emptied`, `ended`, `error`, `loadedmetadata`, `loadstart`, `pause`, `play`, `playing`, `progress`, `ratechange`, `seeked`, `seeking`, `timeupdate`, `volumechange`, `waiting`.

Also emits these Video.js-specific events:

| Event | Description |
| --- | --- |
| `loadcomplete` | |
| `sourcechange` | |

---

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