DEV Community

Cover image for Implement Picture-in-Picture on the Web
Ananya Neogi
Ananya Neogi

Posted on

Implement Picture-in-Picture on the Web

One of my favourite things to do on the web is to implement and test out new and upcoming features. Today we are going to implement Picture-in-Picture.

What is Picture-in-Picture ?

According to W3C Picture-in-Picture Spec-

The specification intends to provide APIs to allow websites to create a floating video window always on top of other windows so that users may continue consuming media while they interact with other content sites, or applications on their device.

While in the PiP(Picture-in-Picture) mode the video is contained in a separate mini window that is always on top of other windows. This window stays visible even when the user agent is not visible.


How to implement Picture-in-Picture ?

HTML -

<video id="videoElement" controls="true" src="demo.mp4"></video>

<!-- button will be used to toggle the PiP mode -->
<button id="togglePipButton">Toggle Picture-in-Picture Mode!</button> 
Enter fullscreen mode Exit fullscreen mode

JavaScript -

1. Call requestPictureInPicture() on click of togglePipButton button element.

requestPictureInPicture() returns a promise.
When the promise resolves, the browser will shrink the video into a mini window that the user can move around and position over other windows.

let video = document.getElementById('videoElement');
let togglePipButton = document.getElementById('togglePipButton');

togglePipButton.addEventListener('click', async function (event) {
    togglePipButton.disabled = true; //disable toggle button while the event occurs
    try {
        // If there is no element in Picture-in-Picture yet, request for it
        if (video !== document.pictureInPictureElement) {
            await video.requestPictureInPicture();
        }
        // If Picture-in-Picture already exists, exit the mode
        else {
            await document.exitPictureInPicture();
        }

    } catch (error) {
        console.log(`Oh Horror! ${error}`);
    } finally {
        togglePipButton.disabled = false; //enable toggle button after the event
    }
});
Enter fullscreen mode Exit fullscreen mode

2. Check for Picture-in-Picture event changes

let video = document.getElementById('videoElement');
video.addEventListener('enterpictureinpicture', function (event) {
    console.log('Entered PiP');
    pipWindow = event.pictureInPictureWindow;
    console.log(`Window size -  \n Width: ${pipWindow.width} \n Height: ${pipWindow.height}`); // get the width and height of PiP window
});

video.addEventListener('leavepictureinpicture', function (event) {
    console.log('Left PiP');
    togglePipButton.disabled = false;
});
Enter fullscreen mode Exit fullscreen mode

We can even update video size based on Picture-in-Picture window size changes by adding a resize event handler. This will be helpful for serving the right quality of video based on the window the user is viewing it on.

3. Always check for feature support

if ('pictureInPictureEnabled' in document) {
    showPipButton();

    // loadedmetadata event occurs when meta data for the specified audio/video has been loaded.Meta data might consists of: duration, dimensions etc.
    video.addEventListener('loadedmetadata', showPipButton);

    // emptied event is fired when the media has become empty, e.g. media has already been loaded or partially loaded.
    video.addEventListener('emptied', showPipButton);
} else {
    console.log('The Picture-in-Picture Web API is not available.');
    togglePipButton.hidden = true;
}

// Enable/disable toggle button depending on whether PiP availability.
function showPipButton() {
    togglePipButton.disabled = (video.readyState === 0) || !document.pictureInPictureEnabled || video.disablePictureInPicture;
}
// video.readyState === 0 means Video metadata have not been loaded yet 
// !document.pictureInPictureEnabled means if Pip is not available
// video.disablePictureInPicture means disablePictureInPicture attribute is present in the video which will result in requestPictureInPicture() rejected promise.
Enter fullscreen mode Exit fullscreen mode

That's it! Your web app is now ready to use Picture-in-Picture!


Bonus! Made a quick demo for this, check it out!

GitHub logo ananyaneogi / picture-in-picture-demo

Upload any video and play it in Picture-in-Picture mode

Picture-in-Picture Demo 🎉

Add any video from your computer and play the video in Picture-in-Picture mode!

Check out the demo now!






Currently the API supports only on the HTMLVideoElement but it states to be extensible in the future.
Check the caniuse stats for browser support. Since this is a progressive enhancement, so regardless of the support, you can use it today on your existing apps! Yay!


References

  1. W3C Picture-in-Picture Spec
  2. Building Modern Web Media Experiences(Chrome Dev Summit 2018)

Top comments (28)

Collapse
 
beaufortfrancois profile image
François Beaufort • Edited

Really nice article Ananya!
I'm glad you enjoyed playing with the Picture-in-Picture Web API ;)

For info, we're currently working on awesome features for the next iteration of this API:

  1. Media Session integration: playback controls in the Picture-in-Picture window such as next track, previous track, etc.)
  2. Auto Picture-in-Picture: gives the browser to ability to automatically enter and exit Picture-in-Picture for a video when it makes sense.

Have a look and let us know what you think!

Collapse
 
ananyaneogi profile image
Ananya Neogi

Thanks! 🙂
The Media Session integration definitely seems like a good idea!
For the auto Picture-in-Picture, the use case you provided for video meetings does seem like a good fit for it however I would think that giving the user an option to enable/disable the auto Picture-in-Picture mode would be nice.

Collapse
 
beaufortfrancois profile image
François Beaufort • Edited

Rest assured that the Auto Picture-in-Picture mode will be available only to web apps user trust enough. See bugs.chromium.org/p/chromium/issue...

Collapse
 
kenedferreira profile image
kened-ferreira

What about multiple picture-in-picture? It would be useful. If it's not possible do this in a same page, maybe one pip per tab should help.

Collapse
 
erebos-manannan profile image
Erebos Manannán

Oh god, this reminds how much I hope people stop implementing these things and making the awful autoplay videos that then follow me around when I didn't care about them in the first place.

This is why I need more and more browser extensions all the time, to block these things.

"so that users may continue consuming media while they interact with other content sites, or applications on their device" - what about the people who hate websites deciding what I want to do?

Collapse
 
ananyaneogi profile image
Ananya Neogi

This is based on user interaction. The user has an option to enable/disable the PiP mode.

Collapse
 
erebos-manannan profile image
Erebos Manannán

Nah, typically it's based on the assumption that the user WANTS it, and "giving me an option" to disable it is just not right. If I, as a brand new user, land on your website and start scrolling past some video, and suddenly it pops out and starts following me around and I then have to stop what I was doing to close that thing, that's not ok.

These things additionally often have awful bugs where e.g. the autoplay on the video might be disabled otherwise (as it ALWAYS should be unless specifically on Youtube or other purely video content website), but then when the video pops out and starts following me around it suddenly starts playing by itself and then I first close it, and then I have to find where it vanished so I can try to figure out how that custom video player (please guys, stop doing that) can be paused. Worst case scenario I have to open developer tools and just delete the DOM nodes to make that thing shut up.

It's like spamming me with popups asking me if I want to sign up for your newsletter, or if I want desktop notifications from your random site? The answer is always no, and developers thinking they are doing good because they're giving me an option to say no is enough, is what pisses me off and why I need so many browser extensions.

Thread Thread
 
korokd profile image
Diogo Korok

The feature is not the problem, it is indeed good that we have these kind of advancements as a platform.
Problem are those who abuse the platform, like Facebook or YouTube.
Want to make an actual difference? I see two ways (each impacting the world differently, though):
1) Boycott abusers. Don't use their apps. Don't give them your money. Call your data back to you, demand them erase your data from their servers (in some countries they must abide by), and go to their competitors.
2) Grow better in your area and, instead of ranting on people online who only wanted to help, seek to have voice in the Working Groups, Consortiums and Committees.

Thread Thread
 
erebos-manannan profile image
Erebos Manannán

You are simply wrong - the feature is the problem.

If I browse the internet randomly I regularly bump into sites abusing various things you would consider "advancements", things like notifications and picture-in-picture.

The reason they are able to abuse these features? Because the features have been designed wrong.

Yes, we should have picture-in-picture, but only if I want it, not when the website developer wants it. We should have notifications, but only when I expressly ask for it, not so every website out there can spam you with "bs-news.com would want to send you notifications? Allow / Deny" dialogs.

Your non-solutions are not amusing.

Thread Thread
 
erebos-manannan profile image
Erebos Manannán

You are simply wrong - the feature is the problem.

If I browse the internet randomly I regularly bump into sites abusing various things you would consider "advancements", things like notifications and picture-in-picture.

The reason they are able to abuse these features? Because the features have been designed wrong.

Yes, we should have picture-in-picture, but only if I want it, not when the website developer wants it. We should have notifications, but only when I expressly ask for it, not so every website out there can spam you with "blahsite would want to send you notifications? Allow / Deny" dialogs.

Your non-solutions are not amusing.

Collapse
 
marvambi profile image
Marvin Ambrose

Case in point #facebook pip. It was an awful experience when the pip feature just decided to have a life of its own like a rogue AI. It annoyed me greatly while experiencing it.

Choice is all that matters for the end users.

Collapse
 
itachiuchiha profile image
Itachi Uchiha

Amazing :) Thanks. Before I heard this, I use our polyfill solution :)

Collapse
 
beaufortfrancois profile image
François Beaufort

Out of curiosity, which polyfill was it?

Collapse
 
itachiuchiha profile image
Itachi Uchiha

Our polyfill similar to this repository github.com/gbentaieb/pip-polyfill/

I know all features won't work if the browser doesn't support.

Collapse
 
himanshisehrawat profile image
himanshiSehrawat

Hey!

I have implemented PIP myself through HTML, but the problem is i need to get the events for closing picture in picture and maximize window separately.
Right now, the event i'm getting is 'leavepictureinpicture'.

If anyone has any thoughts in this one, it would be really helpful.

Thanks

Collapse
 
jay97 profile image
Jamal Al

Awesome, i learned something today. I totally wasn't aware of this feature.

Collapse
 
ben profile image
Ben Halpern

Big fan of this

Collapse
 
sukumaran001 profile image
Sukumaran001

I create the video calling app using webrtc, and i have successfully create the video calling app using Cordova on android and iOS. Next i started to create the Picture-in-Picture mode using JavaScript in my web application that's also works fine, but my mobile app not support requestpictureinpicture mode.

how to enable and controls the JavaScript Picture-in-Picture mode android and iOS device?

Collapse
 
amit_merchant profile image
Amit Merchant

This looks tempting!

Collapse
 
link2twenty profile image
Andrew Bone

I love reading about new features coming to the web!

Collapse
 
ananyaneogi profile image
Ananya Neogi

Likewise!

Collapse
 
thegeoffstevens profile image
Geoff Stevens

Very cool Ananya, the demo worked perfectly for me. It'll be interesting to see how this gets adopted across different sites. Any use cases you're interested in seeing first?

Collapse
 
ananyaneogi profile image
Ananya Neogi

Thanks! 🙂
I spend a lot of time watching conference talks and video shorts on Vimeo so I would love this feature over there. YouTube has implemented a miniplayer feature recently but it only seems useful while you're on YouTube, if PiP gets implemented, we would be able to watch YouTube videos while doing other work too!

Collapse
 
beaufortfrancois profile image
François Beaufort

In the mean time, you can install Picture-in-Picture extension and use the Alt+P keyboard shortcut on YouTube to toggle Picture-in-Picture seamlessly. That's what I do on a daily basis and I love it ;)

Thread Thread
 
ananyaneogi profile image
Ananya Neogi

Ah! Didn't know about this! Thanks for sharing 🙂