# hls-video

Lightweight HLS video element with minimal bundle size

The lightweight HLS video element, optimized for minimal bundle size. The [hls.js video component](https://videojs.org/docs/framework/html/reference/components/hlsjs-video) is the larger, more compatible alternative.

## Import

```ts
import '@videojs/html/media/hls-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/hls-video.js"></script>
```

## Examples

### Basic Usage

**index.html**

```html
<media-container class="media-container">
  <hls-video src="https://stream.mux.com/BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM.m3u8" autoplay muted playsinline loop></hls-video>
</media-container>
```

**index.css**

```css
.media-container {
  position: relative;
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
}
```

**index.ts**

```ts
import '@videojs/html/ui/container';
import '@videojs/html/media/hls-video';
```

## API Reference

### Attributes

Forwards these standard media attributes to the internal `<video>`. See the [MDN media element reference](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/video): `autopictureinpicture`, `autoplay`, `controls`, `controlslist`, `crossorigin`, `disablepictureinpicture`, `disableremoteplayback`, `loading`, `loop`, `muted`, `playsinline`, `poster`, `preload`, `src`.

These Video.js-specific attributes configure media behavior:

| Attribute | Type | Default | Description |
| --- | --- | --- | --- |
| `stream-type` | `'on-demand' \| 'live' \| 'unknown'` | `'unknown'` | The source's stream type — `'live'`, `'on-demand'`, or `'unknown'` until a media playlist has been parsed. Setting a non-`'unknown'` value pins a user override (detection stops updating it); setting `'unknown'` reverts to the engine's detected value. |

### Properties

| Property | Type | Default | Description |
| --- | --- | --- | --- |
| `alternativeMediaSuggestion` | `string \| undefined` | — | Read-only. A complete sentence naming the Media to reach for when this one can't play a source — `Try the hls.js-backed Mux media instead: import the hls-js flavor in place of the spf one.` Appended to the copy this adapter surfaces, and to the notices it logs. Name the flavor, not an import path: a Media is reached through several packages, each with its own counterpart. Empty here: `hls-video` has no better-equipped sibling to point at. A Media that does (a Mux Video built on this engine, whose hls.js-backed counterpart plays MPEG-TS and DRM) overrides this static, and its copy gains the second sentence with no other change. |
| `contentData` | `MediaContentData \| undefined` | — | Read-only. |
| `disableRemotePlayback` | `boolean` | `false` | |
| `engine` | `{ state: { [K in keyof S]-?: Signal<S[K]> }; context: { [K in keyof C]-?: Signal<C[K]> }; destroy(): Promise<void> }` | — | Read-only. Underlying playback engine — the low-level SPF reactive composition that drives playback. An advanced escape hatch for direct engine access; normal playback is driven through this element's own properties and methods. |
| `error` | `{ code: number; message: string; data?: unknown } \| null` | — | Read-only. The current fatal error, or `null`. Only *fatal* conditions appear here — the engine reports non-fatal ones too (they stay in `engine.state.errors`), and promoting them would tell a consumer playback had failed when it hadn't. Resets per source. Fires `'error'` when set. |
| `isFullscreen` | `boolean` | — | Read-only. |
| `isPictureInPicture` | `boolean` | — | Read-only. |
| `liveEdgeStart` | `number` | — | Read-only. Presentation time marking the start of the live-edge window — playback at `currentTime >= liveEdgeStart` counts as "at the live edge" (the same target the engine's `seekToLiveEdge` seeks to: window end − HOLD-BACK). `NaN` when the stream isn't live or nothing is resolved yet. Derived at read time from the engine's live window — no change event; re-read on `timeupdate`/`progress` (as the store's live feature does). |
| `preload` | `'' \| 'none' \| 'metadata' \| 'auto'` | `''` | Preload type (`'none'` / `'metadata'` / `'auto'`). |
| `source` | `{ src?: string; type?: string; drm?: Partial<Record<string, DrmSystemConfig>> } \| null` | `null` | Structured source: the manifest URL plus what a URL cannot carry, which today is the license servers for protected content. Setting it derives `src`. Assigning the same object back costs nothing — changing anything takes a new one. |
| `src` | `string` | `''` | |
| `streamType` | `'on-demand' \| 'live' \| 'unknown'` | `'unknown'` | The source's stream type — `'live'`, `'on-demand'`, or `'unknown'` until a media playlist has been parsed. Setting a non-`'unknown'` value pins a user override (detection stops updating it); setting `'unknown'` reverts to the engine's detected value. |
| `targetLiveWindow` | `number` | — | Read-only. The target live window: `NaN` for on-demand (or unknown), `0` for standard sliding-window live, `Infinity` for DVR (`#EXT-X-PLAYLIST-TYPE:EVENT`). Fires `targetlivewindowchange` on change. |
| `webkitCurrentPlaybackTargetIsWireless` | `boolean \| undefined` | — | Read-only. |
| `webkitPresentationMode` | `WebKitPresentationMode \| undefined` | — | Read-only. |
| `webkitSetPresentationMode` | `((mode: WebKitPresentationMode) => void) \| undefined` | — | Read-only. |

Also exposes these properties from the native media API. See [HTMLVideoElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLVideoElement) for details: `autoplay`, `buffered`, `controls`, `crossOrigin`, `currentSrc`, `currentTime`, `defaultMuted`, `defaultPlaybackRate`, `disablePictureInPicture`, `duration`, `ended`, `loop`, `muted`, `paused`, `playbackRate`, `played`, `playsInline`, `poster`, `readyState`, `remote`, `seekable`, `seeking`, `textTracks`, `title`, `videoHeight`, `videoWidth`, `volume`.

### Methods

Supports these media methods. See [HTMLVideoElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLVideoElement) for details: `addTextTrack`, `canPlayType`, `exitFullscreen`, `exitPictureInPicture`, `load`, `pause`, `play`, `requestFullscreen`, `requestPictureInPicture`.

### Events

Re-dispatches these standard media events from the internal media element: `abort`, `addtrack`, `canplay`, `canplaythrough`, `change`, `contentdatachange`, `durationchange`, `emptied`, `ended`, `enterpictureinpicture`, `leavepictureinpicture`, `loadeddata`, `loadedmetadata`, `loadstart`, `pause`, `play`, `playing`, `progress`, `ratechange`, `removetrack`, `resize`, `seeked`, `seeking`, `stalled`, `suspend`, `timeupdate`, `volumechange`, `waiting`.

Also emits these Video.js-specific events:

| Event | Description |
| --- | --- |
| `error` | Fired when a fatal condition is reported. Read `error` for it. |
| `sourcechange` | Fired when `source` changes. Read `source` for the new value. |
| `streamtypechange` | Fired when the detected stream type changes. Read `streamType` for the new value. |
| `targetlivewindowchange` | Fired when the target live window changes. Read `targetLiveWindow` for the new value. |

### CSS custom properties

| Variable | Description |
| --- | --- |
| `--media-video-border-radius` | Border radius of the video element. |
| `--media-object-fit` | Object fit for the video. |
| `--media-object-position` | Object position for the video. |
| `--media-caption-track-duration` | Duration of the caption track transition. |
| `--media-caption-track-delay` | Delay before the caption track transition. |
| `--media-caption-track-y` | Vertical offset of the caption track. |

---

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