Media Element

Media Chrome will work with any element that exposes the same API as the HTML media elements (<video> and <audio>). This means that you can replace these elements with your own if they conform to the same API. You can read more about the HTMLMediaElement API on MDN.

The simplest media slot is the browser’s native <video> tag. For example:

  <video slot="media" src="https://....mp4" >

In this example, Media controller will:

  • Listen for events emitted from the <video> element
  • Understand the current state of the <video> element by using the known props
  • Call methods on the <video> element like play(), pause(), etc.

The slotted media element is not required to support the complete HTMLMediaElement API. Each Media Chrome component requires different API’s, for example to get the play button working the media element requirements might be:

  • Provide a play() and pause() method
  • Fire play, playing and pause events
  • Provide a paused getter

Here’s an example of how such a custom media element could look like:

class PlayPauseElement extends globalThis.HTMLElement {

  constructor() {

    this.attachShadow({ mode: 'open' });
    this.shadowRoot.innerHTML = `
        :host {
          pointer-events: none;
          display: flex;
          justify-content: center;
          align-items: center;
          color: white;

        :host::before {
          content: 'Paused';

        :host([unpaused])::before {
          content: 'Playing';

  get paused() {
    return !this.hasAttribute('unpaused');

  play() {
    this.toggleAttribute('unpaused', true);
    this.dispatchEvent(new Event('play'));
    this.dispatchEvent(new Event('playing'));
    return Promise.resolve();

  pause() {
    this.toggleAttribute('unpaused', false);
    this.dispatchEvent(new Event('pause'));

if (globalThis.customElements && !globalThis.customElements.get('play-pause')) {
  globalThis.customElements.define('play-pause', PlayPauseElement);

If you’d like to add some extra behavior to the native <video> or <audio> element, have a look at custom-media-element. The HTMLVideoElement API will be automatically added to any custom element that extends from CustomVideoElement.

import { CustomVideoElement } from 'custom-media-element';

class MyCustomVideoElement extends CustomVideoElement {
  constructor() {

  // Override the play method.
  play() {

  // Override the src getter & setter.
  get src() {
    return super.src;

  set src(src) {
    super.src = src;

if (globalThis.customElements && !globalThis.customElements.get('my-custom-video')) {
  globalThis.customElements.define('my-custom-video', MyCustomVideoElement);

export default MyCustomVideoElement;

hls-video-element is a good example making use of this library.

Here are some of the custom media elements that have been built that are compatible with Media Chrome.