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