FrameworkStyle

Features

The state and actions each feature adds to the player

Not every player needs to support every use case. To address this, Video.js has a concept of features — self-contained units of player functionality. Each one adds state properties and actions to the player. For example, “playback” adds paused and play(), “volume” adds volume and setVolume(), and so on.

Using features

Feature bundles and presets

You probably don’t want to hand-pick every feature your player needs. A feature bundle groups the features needed for a specific use case into a single array.

For example, if you import <video-player> from the /video path, you’ll has playback, volume, time, fullscreen, and more already enabled.

<script type="module" src="@videojs/html/video/player"></script>
<video-player>
  <video-skin>
    <video slot="media" src="movie.mp4"></video>
  </video-skin>
</video-player>

Feature bundles are usually paired with specific skins and media elements in a preset . To learn more about this, and the available presets, you’ll want to check out the presets guide.

Create a player with individual features

If you’re not using presets, you can create a player that has individual features.

import { createPlayer, playback, volume, time } from '@videojs/html';

const { ProviderMixin, PlayerController, context } = createPlayer({
  features: [playback, volume, time],
});

class MyPlayer extends ProviderMixin(MediaElement) {
  static readonly tagName = 'my-player';
}

customElements.define('my-player', MyPlayer);

Extending a feature bundle

Since feature bundles are just an array of features under the hood, it doesn’t take much to extend one. For example, if you were using the /background preset and wanted a play button on your background video, you might add the playback feature.

import { createPlayer, playback } from '@videojs/html';
import { backgroundFeatures } from '@videojs/html/background';
import { MediaElement } from '@videojs/html';

const { ProviderMixin } = createPlayer({
  features: [...backgroundFeatures, playback],
});

class MyPlayer extends ProviderMixin(MediaElement) {
  static readonly tagName = 'my-player';
}

customElements.define('my-player', MyPlayer);

Access features in components

You can access feature state and actions through PlayerController and pre-built feature selectors (e.g. selectPlayback, selectVolume):

import { selectPlayback } from '@videojs/html';

// Subscribe to feature state (triggers element updates on change)
readonly #playback = new PlayerController(this, context, selectPlayback);

// Read state and call actions
const media = this.#playback.value;
if (media?.paused) media.play();

Checking for feature support

Volume, fullscreen, and picture-in-picture expose an *Availability property because platform support varies. For example, iOS Safari doesn’t allow programmatic volume control.

Value Meaning
'available' Ready to use
'unavailable' Could work, not ready yet
'unsupported' Platform can never do this

Components that depend on availability (like PiPButton and FullscreenButton) expose a data-availability attribute, so you can hide unsupported controls with CSS:

media-pip-button[data-availability="unsupported"] {
  display: none;
}

You can also check availability in JS:

const media = this.#pip.value;

if (media?.availability === 'unsupported') {
  this.hidden = true;
}