1. Getting Started
  2. Foundation

Getting Started


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


We provide a variety of elements out of the box that help enhance the player. Some provide visual controls such as <vds-play-button> or <vds-time-slider>, and others manage one or many player instances such as <vds-media-sync> or <vds-media-visibility>.

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

You can register an element by importing it from the @vidstack/player/define/* path. When the import is loaded it will safely register the element and any dependencies in the custom elements registry. By 'safely' we mean that the register import paths are safe to use on both client-side and server-side.

Firstly, we register the elements we're using by grabbing the import code snippet from the component's respective docs, or letting autocomplete help us out in our IDE:

        import '@vidstack/player/define/vds-media.js';
import '@vidstack/player/define/vds-video.js';
// Discover elements by typing this in your IDE.
import '@vidstack/player/define/';


The .js extension in the import path is required for Node exports to work. This feature is used so your bundler can import the development or production distribution automatically based on your Node environment setting (NODE_ENV).

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. -->
    <!-- This will immediately render because it's in the light DOM. -->
    <video src="..."></video>
  <!-- ... -->


Define All


The .js extension in the import path is required for Node exports We do not recommend importing everything. By importing dangerously-all.js, you're importing all providers and elements in the library which will bloat your final application bundle size.

We generally recommend only registering what you'll be using. Each element's respective docs contains a register code snippet you can copy and paste as needed. However, you can register all elements if you're testing things out, or in a playground environment like so:

        import '@vidstack/player/define/dangerously-all.js';


You can also register only all UI elements like so (safer):

        import '@vidstack/player/define/dangerously-all-ui.js';


Media Store

The <vds-media> element has a media store that keeps track of the running state of the player. A store in the player is a simple pub/sub mechanism for creating reactive state, updating the value, and subscribing to state changes. The implementation was derived from Svelte Stores.

The store enables you to subscribe directly to specific media state changes, rather than listening to potentially multiple DOM events and binding it yourself.

Tracking media state via events:

        const provider = document.querySelector('vds-video');

let paused = true;

provider.addEventListener('vds-pause', () => {
  paused = true;

provider.addEventListener('vds-play', () => {
  paused = false;


Tracking media state via store subscription:

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

const unsubscribe = media.store.paused.subscribe(($paused) => {
  console.log('Is Paused:', $paused);




We've written the player library with TypeScript, and we distribute all types with the @vidstack/player package. VSCode will detect them by default, but global event types need to be registered separately; otherwise, the following will happen:

        // The event type will default to `Event` instead of `MediaPlayEvent`.
provider.addEventListener('vds-play', (event) => {});


Events are a core part of working with the player library, so we highly recommend you resolve this by adding the following to your TypeScript configuration file:

  "compilerOptions": {
    "types": ["@vidstack/player/globals"]


Element Types

You can import element types directly from the package if you're using TypeScript like so:

        import { type VideoElement, type PlayButtonElement } from '@vidstack/player';

let provider: VideoElement;


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

Event Types

Event types can be imported directly from the package if you're using TypeScript like so:

        import {
  type MediaPlayEvent,
  type MediaCanPlayEvent,
  type MediaTimeUpdateEvent,
} from '@vidstack/player';


All event types are named using PascalCase and suffixed with the word Event (e.g., SliderDragStartEvent). Furthermore, media events are all prefixed with the word Media as seen in the example above.


VSCode provides support for extending the known HTML entities through VSCode Custom Data. Once set up, it enables autocomplete suggestions for custom player elements and on-hover information such as documentation and type data.

Before and after screenshot difference of using the VSCode custom data extension.

  1. Create Settings File

    Create a VSCode settings JSON file at the root of your project directory.

            touch .vscode/settings.json
  2. Add Custom HTML Data

    Add the custom HTML data file path to html.customData inside the newly created settings file.

      "html.customData": ["./node_modules/@vidstack/player/vscode.html-data.json"]

Lit Helpers

The following sections cover helper functions you can use when working with Lit elements.


The mediaStoreSubscription enables you to subscribe directly to specific media state changes like so:

        import { mediaStoreSubscription, LitElement } from '@vidstack/player';

class MyElement extends LitElement {
  constructor() {
    mediaStoreSubscription(this, 'paused', ($paused) => {
      // ...


Your IDE should provide helpful suggestions and docs on the store properties that are available. You can also use the MediaContext interface on GitHub as a reference.


The MediaRemoteControl class provides a simple facade for dispatching media request events. This can be used to request media playback to play/pause, change the current volume level, seek to a different time position, and other actions that change media state.

        import { html, LitElement } from 'lit';
import { MediaRemoteControl } from '@vidstack/player';

class PlayButtonElement extends LitElement {
  protected _remote = new MediaRemoteControl(this);

  protected _makePlayRequest(triggerEvent: Event) {
      // - We are providing the "triggerEvent" here.
      // - Trigger events allow us to trace events back to their origin.
      // - The media play event will have this pointer event in its chain.

  function render() {
    return html`
      <button @pointerup=${this._makePlayRequest}>
        <!-- ... -->


Your IDE should provide helpful suggestions and docs on the available methods. You can also use the MediaRemoteControl source on GitHub as a reference.