Start · Sprachen · JavaScript · Referenz · ShadowRoot.pictureInPictureElement

ShadowRoot.pictureInPictureElement

Eigenschaft

Gibt das <code>&lt;video&gt;</code>-Element innerhalb dieses Shadow-Trees zurück, das gerade im Bild-in-Bild-Modus läuft, oder <code>null</code>.

seit JavaScript Chrome/Edge 70+, Safari 13.1+ (Firefox: nicht unte Kategorie: webapi

Signatur

ShadowRoot.pictureInPictureElement

Beschreibung

Die schreibgeschützte Eigenschaft pictureInPictureElement eines ShadowRoot liefert das Element, das aktuell im Bild-in-Bild-Fenster (Picture-in-Picture, kurz PiP) angezeigt wird, sofern es zu diesem Shadow-Tree gehört. Ist kein Element im PiP-Modus oder liegt es außerhalb dieses Shadow-Trees, ist der Wert null.

Die Eigenschaft ist das Gegenstück zu Document.pictureInPictureElement. Wegen der Kapselung von Shadow DOM gibt document.pictureInPictureElement bei einem Video innerhalb einer Web-Komponente nur den Shadow-Host zurück (Retargeting), nicht das eigentliche <video>. Innerhalb der Komponente fragt man deshalb this.shadowRoot.pictureInPictureElement ab, um das konkrete Element zu erhalten.

Typische Einsatzfälle sind eigene Video-Player als Custom Elements: Schaltflächen-Zustände („PiP ein/aus“) aktualisieren, prüfen, ob das eigene Video bereits schwebt, oder vor dem Entfernen der Komponente den PiP-Modus sauber beenden.

Rückgabewert

Typ
Element | null
Beschreibung
Das im Bild-in-Bild-Modus dargestellte Element (in der Praxis ein HTMLVideoElement) innerhalb dieses Shadow-Trees, sonst null.

Beispiele

PiP-Umschalter in einer Web-Komponente

class VideoPlayer extends HTMLElement {
  constructor() {
    super();
    const root = this.attachShadow({ mode: 'open' });
    root.innerHTML = `
      <video src="film.mp4" controls></video>
      <button>Bild-in-Bild</button>`;
    this.video = root.querySelector('video');
    root.querySelector('button').addEventListener('click', () => this.togglePip());
  }

  async togglePip() {
    try {
      if (this.shadowRoot.pictureInPictureElement) {
        await document.exitPictureInPicture();
      } else {
        await this.video.requestPictureInPicture();
      }
    } catch (err) {
      console.error('PiP fehlgeschlagen:', err.message);
    }
  }
}
customElements.define('video-player', VideoPlayer);

Unterschied zwischen Document und ShadowRoot (Retargeting)

const player = document.querySelector('video-player');
const video = player.shadowRoot.querySelector('video');

video.addEventListener('enterpictureinpicture', () => {
  console.log(document.pictureInPictureElement === player);          // Host
  console.log(player.shadowRoot.pictureInPictureElement === video);   // echtes Video
});

button.addEventListener('click', () => video.requestPictureInPicture());
true true

Button-Zustand synchron halten und beim Entfernen aufräumen

class PipVideo extends HTMLElement {
  connectedCallback() {
    const root = this.shadowRoot ?? this.attachShadow({ mode: 'open' });
    root.innerHTML = '<video src="clip.mp4" controls></video><button>PiP</button>';
    const video = root.querySelector('video');
    const btn = root.querySelector('button');
    const update = () => {
      btn.textContent = root.pictureInPictureElement ? 'PiP beenden' : 'PiP starten';
    };
    video.addEventListener('enterpictureinpicture', update);
    video.addEventListener('leavepictureinpicture', update);
    btn.disabled = !document.pictureInPictureEnabled;
    update();
  }

  disconnectedCallback() {
    if (this.shadowRoot?.pictureInPictureElement) {
      document.exitPictureInPicture().catch(() => {});
    }
  }
}
customElements.define('pip-video', PipVideo);

// Wichtig · Fallstricke

  • Browser-Kompatibilität: In Chromium-Browsern (Chrome, Edge, Opera) und Safari verfügbar, Firefox unterstützt die Picture-in-Picture-API nicht (nur eine eigene UI-Funktion ohne JS-API). Vorher per 'pictureInPictureElement' in ShadowRoot.prototype bzw. document.pictureInPictureEnabled prüfen.
  • Die Eigenschaft ist schreibgeschützt. PiP startet man mit HTMLVideoElement.requestPictureInPicture() und beendet es mit document.exitPictureInPicture(). Eine Methode dafür auf ShadowRoot gibt es nicht.
  • Es kann dokumentweit immer nur ein Element im PiP-Modus sein. Liegt es außerhalb dieses Shadow-Trees, ist der Wert null, auch wenn gerade ein PiP-Fenster offen ist.
  • Bei geschlossenen Shadow-Roots (mode: 'closed') kommt man von außen nicht an shadowRoot heran. Die Referenz auf den Root muss man dann in der Komponente selbst speichern.
  • requestPictureInPicture() braucht eine Nutzeraktion (z. B. einen Klick). Sonst wird das Promise mit NotAllowedError abgelehnt.
  • Nicht zu verwechseln mit der neueren Document Picture-in-Picture API (documentPictureInPicture), die beliebiges HTML in einem PiP-Fenster anzeigt.