1. Core Concepts
  2. Components

Core Concepts


In this section, we'll go through the basics of working with the custom elements in Vidstack Player.


We provide a variety of components out of the box that help enhance the player.

Some are concerned with layout such as <media-player> and <media-outlet>, some provide visual controls such as <media-play-button> or <media-time-slider>, and others manage player instances.

We recommend either searching (cmd + k) for what you're looking for or browsing the sidebar. Each element contains documentation on how to use/style it, and an API reference.

You can register all elements like so:

        import { defineCustomElements } from 'vidstack/elements';



Or, individually like so:

        // The `.js` extension is required.
import 'vidstack/define/media-player.js';
import 'vidstack/define/media-poster.js';


Next, we can use the defined elements and the browser will "upgrade" them once the script above has loaded and run.

        <!-- Browser will upgrade custom elements once they're defined. -->


Attach Hook

Vidstack elements go through a two-step process in which they're defined then attached before they're finally ready to be interacted with:

        const player = document.querySelector('media-player');

// 1. Like any other custom element it needs to be defined:
customElements.whenDefined('media-player', () => {
  // `media-player` is now defined.

  // 2. Wait for the custom element instance to be attached.
  player.onAttach(() => {
    // Safe to now interact with instance props/methods.


You can await the defineCustomElements call to ensure all elements are defined:

        import { defineCustomElements } from 'vidstack/elements';

async function onLoad() {
  await defineCustomElements();
  const player = document.querySelector('media-player');
  player.onAttach(() => {
    // ...

document.addEventListener('load', onLoad, { once: true });


Keep Alive

By default, Vidstack elements will be destroyed when they've disconnected from the DOM and have not re-connected after an animation frame tick. You can specify that an element should be kept alive like so:

        <!-- Keep this element and all children alive until manually destroyed. -->
<media-player keep-alive>
  <!-- This will be kept alive as well. -->
  <!-- ... -->


Now, you can manually destroy the element instance and all children by calling the destroy() method on the element that you specified to keep alive like so:

        const player = document.querySelector('media-player');
// This will destroy the player element instance and all child instances.


You don't need to worry about keeping elements alive if you're using a framework integration such as React. Elements will be disposed of correctly based on the framework lifecycle.


Most component props can be set directly in HTML via attributes like so:

        <!-- The following will set the `type` and `format` props. -->
<media-time type="current" format="time"></media-time>


All attributes in Vidstack are the kebab-case variant of the property name. For example, the fooBar property would be the attribute foo-bar.


Events can be listened to by obtaining a reference to the element instance and attaching an event listener like so:

        const player = document.querySelector('media-player');

player.addEventListener('play', function onPlay() {
  // ...



Obtaining a reference to the element instance enables you to manipulate the custom element itself and directly call properties/methods like so:

        const player = document.querySelector('media-player');

player.onAttach(() => {
  // Set a instance property:
  player.muted = true;

  // Call a instance method:


Element Types

All element types are classes named using PascalCase and suffixed with the word Element (e.g., MediaPlayerElement).

        import { type MediaPlayerElement, type MediaPosterElement } from 'vidstack';

let player: MediaPlayerElement;


Provider Types

The following utilities can be useful for narrowing the type of a media provider:

        import {
  type AudioProvider,
  type HLSProvider,
  type MediaProvider,
  type VideoProvider,
} from 'vidstack';

const player = document.querySelector('media-player');

player.addEventListener('provider-change', (event) => {
  const provider = event.detail;

  if (isAudioProvider(provider)) {
    const audioElement = provider.audio;

  if (isVideoProvider(provider)) {
    const videoElement = provider.video;

  if (isHLSProvider(provider)) {
    provider.config = { lowLatencyMode: true };
    provider.onInstance((hls) => {
      // ...