Using the Document Picture-in-Picture API
=========================================

**Experimental:** **This is an experimental technology**  
Check the Browser compatibility table carefully before using this in production.

**Secure context:** This feature is available only in secure contexts (HTTPS), in some or all supporting browsers.

This guide provides a walkthrough of typical usage of the Document Picture-in-Picture API.

**Note:** You can see the featured demo in action at Document Picture-in-Picture API Example (see the full source code also).

Sample HTML
-----------

The following HTML sets up a basic video player.


```html
<div id="container">
  <p class="in-pip-message">
    Video player is currently in the separate Picture-in-Picture window.
  </p>
  <div id="player">
    <video
 src="assets/bigbuckbunny.mp4"
 id="video"
 controls
 width="320"></video>

    <div id="credits">
      <a href="https://peach.blender.org/download/" target="\_blank">
        Video by Blender </a
 >;
      <a href="https://peach.blender.org/about/" target="\_blank">
        licensed CC-BY 3.0
      </a>
    </div>

    <div id="controlbar">
      <p class="no-picture-in-picture">
        Document Picture-in-Picture API not available
      </p>

      <p></p>
    </div>
  </div>
</div>
```

Feature detection
-----------------

To check if the Document Picture-in-Picture API is supported, you can test whether `documentPictureInPicture` is available on `window`:


```js
if ("documentPictureInPicture" in window) {
  document.querySelector(".no-picture-in-picture").remove();

  const togglePipButton = document.createElement("button");
  togglePipButton.textContent = "Toggle Picture-in-Picture";
  togglePipButton.addEventListener("click", togglePictureInPicture, false);

  document.getElementById("controlbar").appendChild(togglePipButton);
}
```


If it is available, we remove the "Document Picture-in-Picture API not available" message and instead add a `<button>` element to open the video player in a Document Picture-in-Picture window.

Open a Picture-in-Picture window
--------------------------------

The following JavaScript calls `window.documentPictureInPicture.requestWindow()` to open a blank Picture-in-Picture window. The returned `Promise` fulfills with a Picture-in-Picture `Window` object. The video player is moved to that window using `Element.append()`, and we display the message informing the user that it has been moved.

The `width` and `height` options of `requestWindow()` set the Picture-in-Picture window to the desired size. Browsers may clamp the option values if they are too large or too small to fit a user-friendly window size.


```js
async function togglePictureInPicture() {
  // Returns null if no pip window is currently open
  if (!!window.documentPictureInPicture.window) {
    // Open a Picture-in-Picture window.
    const pipWindow = await documentPictureInPicture.requestWindow({
      width: videoPlayer.clientWidth,
      height: videoPlayer.clientHeight,
    });

    // ...

    // Move the player to the Picture-in-Picture window.
    pipWindow.document.body.append(videoPlayer);

    // Display a message to say it has been moved
    inPipMessage.style.display = "block";
  }
}
```

Copy style sheets to the Picture-in-Picture window
--------------------------------------------------

To copy all CSS style sheets from the originating window, loop through all style sheets explicitly linked into or embedded in the document (via `Document.styleSheets`) and append them to the Picture-in-Picture window. Note that this is a one-time copy.


```js
// ...

// Copy style sheets over from the initial document
// so that the player looks the same.
[...document.styleSheets].forEach((styleSheet) => {
  try {
    const cssRules = [...styleSheet.cssRules]
      .map((rule) => rule.cssText)
      .join("");
    const style = document.createElement("style");

    style.textContent = cssRules;
    pipWindow.document.head.appendChild(style);
  } catch (e) {
    const link = document.createElement("link");

    link.rel = "stylesheet";
    link.type = styleSheet.type;
    link.media = styleSheet.media;
    link.href = styleSheet.href;
    pipWindow.document.head.appendChild(link);
  }
});

// ...
```

Handle when the Picture-in-Picture window closes
------------------------------------------------

The code for toggling the Picture-in-Picture window closed again when the button is pressed a second time looks like this:


```js
inPipMessage.style.display = "none";
playerContainer.append(videoPlayer);
window.documentPictureInPicture.window.close();
```


Here we reverse the DOM changes — hiding the message and putting the video player back in the player container in the main app window. We also close the Picture-in-Picture window programmatically using the `Window.close()` method.

However, you also need to consider the case where the user closes the Picture-in-Picture window by pressing the browser supplied close (X) button on the window itself. You can handle this by detecting when the window closes using the `pagehide` event:


```js
pipWindow.addEventListener("pagehide", (event) => {
  inPipMessage.style.display = "none";
  playerContainer.append(videoPlayer);
});
```

Listen to when the website enters Picture-in-Picture
----------------------------------------------------

Listen to the `enter` event on the `DocumentPictureInPicture` instance to know when a Picture-in-Picture window is opened.

In our demo, we use the `enter` event to add a mute toggle button to the Picture-in-Picture window:


```js
documentPictureInPicture.addEventListener("enter", (event) => {
  const pipWindow = event.window;
  console.log("Video player has entered the pip window");

  const pipMuteButton = pipWindow.document.createElement("button");
  pipMuteButton.textContent = "Mute";
  pipMuteButton.addEventListener("click", () => {
    const pipVideo = pipWindow.document.querySelector("#video");
    if (!pipVideo.muted) {
      pipVideo.muted = true;
      pipMuteButton.textContent = "Unmute";
    } else {
      pipVideo.muted = false;
      pipMuteButton.textContent = "Mute";
    }
  });

  pipWindow.document.body.append(pipMuteButton);
});
```


**Note:** The `DocumentPictureInPictureEvent` event object contains a `window` property to access the Picture-in-Picture window.

Access elements and handle events
---------------------------------

You can access elements in the Picture-in-Picture window in several different ways:

* The `Window` instance returned by the `DocumentPictureInPicture.requestWindow()` method, as seen above.
* Via the `window` property of the `DocumentPictureInPictureEvent` event object (on the `enter` event), as seen above.
* Via the `DocumentPictureInPicture.window` property:


```js
const pipWindow = window.documentPictureInPicture.window;
if (pipWindow) {
  // Mute video playing in the Picture-in-Picture window.
  const pipVideo = pipWindow.document.querySelector("#video");
  pipVideo.muted = true;
}
```


Once you've got a reference to the Picture-in-Picture `window` instance, you can manipulate the DOM (for example creating buttons) and respond to user input events (such as `click`) as you would do normally in the regular browser window context.