fbpx

Use Picture-in-Picture Web API

Table of Content:

Introduction:

Many users want to continue consuming media while they interact with other content, sites, or applications on their device. For this type of activity Picture-in-Picture web browser feature is best.

In picture-in-picture, the video is contained in a separate miniature window that is always on top of other windows.

This specification aims to allow websites to initiate and control this behavior by exposing the following sets of properties to the API:

  • Notify the website when it enters and leaves Picture-in-Picture mode.
  • Allow the website to trigger Picture-in-Picture mode via a user gesture on a video element.
  • Allow the website to know the size of the Picture-in-Picture window and notify the website when it changes.
  • Allow the website to exit Picture-in-Picture mode.
  • Allow the website to check if Picture-in-Picture mode can be triggered.
<video id="video" src="https://example.com/file.mp4"></video>
<button id="togglePipButton"></button>
<script> 
//other code
</script>

Request or Exit Picture-in-Picture:

The Picture-in-Picture Web API may not be supported, so you have to detect this to provide progressive enhancement. Even when it is supported, it may be turned off by the user or disabled by a feature policy.

We can use the new boolean document.pictureInPictureEnabled to determine this.

<script>
  const video = document.getElementById("video");
  const togglePipButton = document.getElementById("togglePipButton");

  // Hide button if Picture-in-Picture is not supported or disabled.
  togglePipButton.hidden =   !document.pictureInPictureEnabled || video.disablePictureInPicture;
//.................
</script>

At line 6 we are hiding the PipButton if this feature is disabled or not supported

<script>
// other code
togglePipButton.addEventListener("click", async () => {
    // If there is no element in Picture-in-Picture yet, let’s request
    // Picture-in-Picture for the video, otherwise leave it.
    try {
      if (document.pictureInPictureElement) {
        await video.requestPictureInPicture();
      } else {
        await document.exitPictureInPicture();
      }
    } catch (err) {
      // Video failed to enter/leave Picture-in-Picture mode.
    }
  });
</script>

If Picture-in-Picture support is false, throw a NotSupportedError and abort other steps. If the document is not allowed to use "picture-in-picture", throw a SecurityError and abort other steps. Even you throw an InvalidStateError and abort these steps. if video’s is ablePictureInPicture is true.

While entering and exiting Picture-in-Picture. We first have to check if the read-only object document.pictureInPictureElement is our video element. If it isn’t, we send a request to enter Picture-in-Picture as above.

Otherwise, we ask to leave by calling document.exitPictureInPicture(), which means the video will appear back in the original tab.

If pictureInPictureElement is fullscreenElement, it is RECOMMENDED to exit fullscreen.

Monitor video Picture-in-Picture changes:

<script>
  const video = document.getElementById("video");
  // other code
  video.addEventListener("enterpictureinpicture", (event) => {
    // Video entered Picture-in-Picture mode.
    const pipWindow = event.pictureInPictureWindow;
    console.log(`Picture-in-Picture window width: ${pipWindow.width}`);
    console.log(`Picture-in-Picture window height: ${pipWindow.height}`);
  });

  video.addEventListener("leavepictureinpicture", () => {
    // Video left Picture-in-Picture mode.
  });
</script>

Auto Picture-in-Picture

Some pages may want to automatically enter and leave Picture-in-Picture for a video element; for example, video meeting web apps would benefit from some automatic Picture-in-Picture behavior when the user switches back and forth between the web app and other applications/tabs.

To support these use cases, a new autoPictureInPicture an attribute is added to the list of content attributes for video elements.

<video id="video" autopictureinpicture src="example.mp4"></video>

<script>
video.addEventListener('enterpictureinpicture', function(event) {
  consolelog('Video entered Picture-in-Picture');
});

video.addEventListener('leavepictureinpicture', function(event) {
  console.log(' Video left Picture-in-Picture');
});

/* Feature support */

if (!('autoPictureInPicture' in HTMLVideoElement.prototype)) {
  console.log('Warning! Auto Picture-in-Picture is not available.');
}
</script>

Complete code:

<html>
  <body>
    <video
      id="video" controls src="Google-Search-01.mp4" style="width: 80%; height: auto;" autopictureinpicture></video>
    <button id="pipButton" disabled>Enter Picture-in-Picture mode</button>
  </body>

  <script>
    const video = document.getElementById("video");
    const pipButton = document.getElementById("pipButton");

    if ("pictureInPictureEnabled" in document) {
      // Enable button if Picture-in-Picture is supported.
      pipButton.disabled = false;
      pipButton.addEventListener("click", () => {
        // If there is no element in Picture-in-Picture yet, let’s request
        // Picture-in-Picture for the video, otherwise leave it.
        if (document.pictureInPictureElement) {
          document.exitPictureInPicture().catch((error) => {
            // Error handling
            console.log(error);
          });
        } else {
          video.requestPictureInPicture().catch((error) => {
            // Error handling
            console.log(error);
          });
        }
      });
    }

    video.addEventListener("enterpictureinpicture", () => {
      pipButton.textContent = "Exit Picture-in-Picture mode";
    });

    video.addEventListener("leavepictureinpicture", () => {
      pipButton.textContent = "Enter Picture-in-Picture mode";
    });
if (!('autoPictureInPicture' in HTMLVideoElement.prototype)) {
  alert('Warning! Auto Picture-in-Picture is not available.');
}
  </script>
</html>

References