attributes

Theme

This attribute is designed to offer developers a seamless way to customize the visual experience of the video player. Choosing a theme is a breeze, simply add the theme attribute to the <mave-player> tag.

<mave-player embed="{embed id}" theme="synthwave"></mave-player>

Themes

Label Description
dolphin All controls are grouped in a single transparent bar.
synthwave The time scrubber is above the controls in this theme.

Preview

External themes

Create your own player controls and styling with a JavaScript theme:

<mave-player embed="{embed id}" theme="/themes/brand.js"></mave-player>

Use a path relative to your page or a full URL. The names default, dolphin and synthwave select the built-in themes. For updates, add a version to the URL, such as /themes/brand.js?v=2. If loading fails, the player uses the default theme.

Create a theme

Mave includes the Media Chrome controls and menus. Use them in your theme with your own HTML and CSS. See the styling guide for CSS variables and custom icons. Available controls depend on browser and media support.

Export build(name, LitElement, html, css) from your JavaScript file. Mave provides the Lit helpers; register your component with customElements.define(`theme-${name}`, YourTheme) using the supplied name.

Inside <media-controller>, include <slot name="media" slot="media"> for the video. Keep the poster slot and #subtitles_text to display the poster and subtitles. For Mave audio tracks, use <mave-audio-track-menu> with <mave-audio-track-menu-button>.

Serve the file as JavaScript and enable CORS when hosting it on another origin. Optional global styles, such as fonts, can go in /themes/brand.css alongside the module.

Example

A floating control bar with a blue play button and a slim timeline. All styling is included in the theme file.

Result

Code

Save this as /themes/brand.js:

export function build(name, LitElement, html, css) {
  class BrandTheme extends LitElement {
    static styles = css`
      :host {
        display: block;
        width: 100%;
        height: 100%;
        overflow: hidden;
        border-radius: 22px;
      }
      media-controller {
        width: 100%;
        height: 100%;
        container-type: inline-size;
        --media-primary-color: #253048;
        --media-secondary-color: transparent;
        --media-control-background: transparent;
        --media-control-hover-background: rgb(37 48 72 / 7%);
        --media-focus-box-shadow: inset 0 0 0 2px #365df5;
        --media-range-track-height: 3px;
        --media-range-track-background: rgb(37 48 72 / 16%);
        --media-range-bar-color: #365df5;
        --media-range-thumb-background: #365df5;
        --media-range-thumb-width: 8px;
        --media-range-thumb-height: 8px;
      }
      ::slotted(video) {
        display: block;
        width: 100%;
        height: 100%;
        object-fit: contain;
      }
      media-control-bar {
        box-sizing: border-box;
        align-items: center;
        gap: 8px;
        width: calc(100% - 32px);
        max-width: 680px;
        margin: 0 auto 16px;
        padding: 7px;
        border: 1px solid rgb(255 255 255 / 70%);
        border-radius: 999px;
        background: rgb(250 250 248 / 90%);
        box-shadow: 0 6px 24px rgb(15 23 42 / 18%);
        -webkit-backdrop-filter: blur(16px);
        backdrop-filter: blur(16px);
      }
      media-play-button, media-mute-button, media-fullscreen-button {
        flex-shrink: 0;
        overflow: hidden;
        border-radius: 50%;
        --media-button-padding: 12px;
        --media-button-icon-width: 18px;
        --media-button-icon-height: 18px;
      }
      media-play-button {
        box-shadow: 0 2px 6px rgb(54 93 245 / 24%);
        --media-primary-color: white;
        --media-control-background: #365df5;
        --media-control-hover-background: #2447d5;
      }
      media-time-range, media-time-display {
        --media-control-hover-background: transparent;
      }
      media-time-range {
        flex: 1;
        min-width: 0;
        --media-text-color: white;
        --media-preview-time-background: #253048;
        --media-preview-time-text-shadow: none;
        --media-preview-time-padding: 6px 10px;
      }
      media-time-display {
        flex-shrink: 0;
        color: #5b6475;
        font: 500 12px/1 system-ui, sans-serif;
        font-variant-numeric: tabular-nums;
        --media-control-padding: 0 4px;
      }
      #subtitles_text {
        position: absolute;
        inset: auto 5% 80px;
        color: white;
        font: 600 18px/1.4 system-ui, sans-serif;
        text-align: center;
        text-shadow: 0 1px 4px black;
        pointer-events: none;
      }
      @container (max-width: 440px) {
        media-time-display { display: none; }
      }
    `;

    render() {
      return html`
        <media-controller>
          <slot name="media" slot="media"></slot>
          <slot name="poster" slot="poster"></slot>
          <media-control-bar>
            <media-play-button></media-play-button>
            <media-time-range></media-time-range>
            <media-time-display showduration></media-time-display>
            <media-mute-button></media-mute-button>
            <media-fullscreen-button></media-fullscreen-button>
          </media-control-bar>
          <div id="subtitles_text"></div>
        </media-controller>
      `;
    }
  }

  customElements.define(`theme-${name}`, BrandTheme);
}

Use it with your video. Set the corner radius on the player too, so the loading poster has the same rounded corners:

<mave-player
  embed="{embed id}"
  theme="/themes/brand.js"
  style="border-radius: 22px; overflow: hidden;"
></mave-player>
🍪 Press 'Accept' to confirm that you accept we don't use cookies. Yes, this banner is just for show!
Accept