# HTML API
HTML-specific concerns: element naming, imports, skins.
## Element Naming
| Layer | Pattern | Examples |
| ------ | ---------------------------- | ---------------------------------------------- |
| Player | `<{mediatype}-player>` | ``, `` |
| Skin | `<{mediatype}-skin>` | ``, `` |
| Media | `<{source}-{mediatype}>` | ``, ``, `` |
| UI | `` | ``, `` |
### Special Players
Only fundamentally different behaviors get their own player:
```html
```
## Import Paths
Grouped by use case, then by concern:
### Video (default)
```ts
import '@videojs/html/video/player'; // includes features.video
import '@videojs/html/video/skin';
import '@videojs/html/video/skin.css';
```
### Audio (default)
```ts
import '@videojs/html/audio/player'; // includes features.audio
import '@videojs/html/audio/skin';
import '@videojs/html/audio/skin.css';
```
### Background Video
```ts
import '@videojs/html/background/player'; // includes features.background
import '@videojs/html/background/skin';
import '@videojs/html/background/skin.css';
```
### Features (additive)
```ts
import '@videojs/html/feature/streaming';
import '@videojs/html/feature/ads';
import '@videojs/html/feature/live';
import '@videojs/html/feature/chapters';
// Granular
import '@videojs/html/feature/quality-selection';
import '@videojs/html/feature/audio-tracks';
import '@videojs/html/feature/text-tracks';
```
### Media
```ts
import '@videojs/html/media/hls-video';
import '@videojs/html/media/hls-audio';
import '@videojs/html/media/dash-video';
```
### UI Primitives (for custom skins)
```ts
import '@videojs/html/ui/menu';
import '@videojs/html/ui/radio-group';
import '@videojs/html/ui/slider';
```
## Registration Models
### Side-Effect Imports (Declarative)
Elements register globally when imported:
```ts
import '@videojs/html/video/player';
import '@videojs/html/video/skin';
```
```html
```
### createPlayer (Programmatic)
For custom element names or full control:
```ts
import { createPlayer } from '@videojs/html';
import { features } from '@videojs/core/dom';
const { PlayerElement, PlayerController, context } = createPlayer({
features: [...features.video],
});
customElements.define('my-video-player', PlayerElement);
```
```html
```
### Mixins (Advanced)
When you need to extend behavior or split provider/container:
```ts
import { createPlayer, MediaElement } from '@videojs/html';
import { features } from '@videojs/core/dom';
const { PlayerMixin, ProviderMixin, ContainerMixin } = createPlayer({
features: [...features.video],
});
// Combined player (provider + container)
class MyPlayer extends PlayerMixin(MediaElement) {
// Custom logic
}
// Or split for advanced cases
class MyProvider extends ProviderMixin(MediaElement) {}
class MyContainer extends ContainerMixin(MediaElement) {}
```
## PlayerElement
The simplest way to create a player element:
```ts
import { createPlayer } from '@videojs/html';
import { features } from '@videojs/core/dom';
const { PlayerElement } = createPlayer({
features: [...features.video],
});
customElements.define('video-player', PlayerElement);
```
`PlayerElement` is a complete player that:
- Creates and manages the store
- Provides context to descendants
- Auto-attaches media elements
- Handles cleanup on disconnect
## Skins
### Adaptive Skins
Default skin adapts to available features:
```ts
import '@videojs/html/video/player';
import '@videojs/html/feature/streaming'; // skin will show quality menu
import '@videojs/html/video/skin';
```
```html
```
### Named Skins
Specific UI compositions and style variants:
```html
```
### Skin Customization
Default skin handles optional feature UI via lazy loading.
**Ejected skin structure:**
```
skin/
video/
video-skin.ts
video-skin.css
features.ts
```
## MediaElement Base Class
Base class for UI primitives. No shadow DOM — the host element IS the control.
```ts
import { MediaElement, PlayerController } from '@videojs/html';
import { selectPlayback } from '@videojs/core/dom';
export class MediaPlayButton extends MediaElement {
#playback = new PlayerController(this, context, selectPlayback);
override connectedCallback() {
super.connectedCallback();
this.addEventListener('click', this.#handleClick);
}
#handleClick = () => {
this.#playback.value?.toggle();
};
override update() {
const playback = this.#playback.value;
if (!playback) return;
this.setAttribute('aria-pressed', String(!playback.paused));
}
}
```
```ts
// define/ui/media-play-button.ts (side-effect import)
import { MediaPlayButton } from '../src/ui/media-play-button.js';
customElements.define('media-play-button', MediaPlayButton);
```
**Usage:**
```ts
import '@videojs/html/ui/media-play-button';
```
## PlayerController
Reactive controller for accessing player state. Triggers `update()` when subscribed state changes.
### Constructor
```ts
// Without selector — store access only, no subscription
new PlayerController(host, context)
// With selector — subscribes, triggers update on change
new PlayerController(host, context, selector)
```
### Example
```ts
import { MediaElement, PlayerController } from '@videojs/html';
import { selectVolume } from '@videojs/core/dom';
export class MediaVolumeSlider extends MediaElement {
#volume = new PlayerController(this, context, selectVolume);
override connectedCallback() {
super.connectedCallback();
this.addEventListener('input', this.#handleInput);
}
#handleInput = (e: Event) => {
this.#volume.value?.setVolume(parseFloat((e.target as HTMLInputElement).value));
};
override update() {
const volume = this.#volume.value;
if (!volume) return;
(this as unknown as HTMLInputElement).value = String(volume.volume);
}
}
```
### Controller API
| Property | Type | Description |
| -------- | ---------------- | ---------------------------------------------------- |
| `store` | `Store` | Direct store access |
| `value` | `R \| undefined` | Selected state (with selector) or snapshot (without) |
## Mixins
For advanced customization when you need to extend behavior.
### PlayerMixin
Combined provider + container in one element:
```ts
const { PlayerMixin } = createPlayer({
features: [...features.video],
});
class MyPlayer extends PlayerMixin(MediaElement) {
// Custom player logic
}
```
### ProviderMixin
Provider-only — creates store and provides context:
```ts
const { ProviderMixin } = createPlayer({
features: [...features.video],
});
class MyProvider extends ProviderMixin(MediaElement) {
// Custom provider logic
}
```
### ContainerMixin
Container-only — consumes context and auto-attaches media:
```ts
const { ContainerMixin } = createPlayer({
features: [...features.video],
});
class MyContainer extends ContainerMixin(MediaElement) {
// Custom container logic
}
```
### Split Provider/Container
When media element and container need different DOM locations:
```html
```
## Full Example
```ts
// main.ts
import '@videojs/html/video/player';
import '@videojs/html/feature/streaming';
import '@videojs/html/media/hls-video';
import '@videojs/html/video/skin.css';
import '@videojs/html/video/skin';
```
```html
```