GuidePlayback
Use picture-in-picture
Pop the video into a floating window, with availability detection and state that tracks every entry path.
Recommended approach
Add a PiPButton. It requests and exits picture-in-picture, reflects the current state, and renders nothing when picture-in-picture is unsupported.
How it works
The picture-in-picture feature puts three things in player state.
pip is true while the video is in a floating window. It tracks every way in and out — your button, the native controls, or a control the browser adds on its own.
pipAvailability answers “can I offer this?” It starts as 'unavailable'. Once the feature attaches to a media element, it settles to 'available' or 'unsupported'.
requestPictureInPicture(), exitPictureInPicture(), and togglePictureInPicture() change the presentation. If the browser blocks a request, the returned promise rejects. In a browser with no picture-in-picture API, the actions resolve without changing anything.
Picture-in-picture and fullscreen are exclusive: requesting one exits the other first.
Availability and constraints
- Show picture-in-picture controls only when
pipAvailabilityis'available'. PiPButton handles this for you. - Requests must come from a user gesture; browsers reject requests outside one.
- Firefox 153 (July 2026) added the programmatic picture-in-picture API. Earlier versions, including Firefox ESR 140, report
'unsupported'even though they offer their own built-in picture-in-picture toggle to users. - On iOS, picture-in-picture is supported on iPhone and iPad through the WebKit presentation mode; the player handles this path for you.
- The browser owns the floating window: its size, position, and built-in controls aren’t yours to style.
- The user can close the window or return the video at any time. React to
pipstate instead of assuming your button is the only entry and exit.
Common variations
Request picture-in-picture from app logic
Enter picture-in-picture when the user scrolls the player out of view or navigates within your app. This still requires a recent user gesture in most browsers, so tie it to an interaction:
Troubleshooting
The picture-in-picture button doesn’t render
pipAvailability is 'unsupported' — the browser has no programmatic picture-in-picture API (Firefox before 153), or the media isn’t a video.
The request rejects
The video has no data yet (wait for it to be ready), the call wasn’t tied to a user gesture, or the browser blocked it. Handle the rejection rather than assuming entry succeeded.
State is wrong after the user closes the floating window
Read pip from player state instead of tracking entry and exit yourself; it stays in sync with every path in and out of picture-in-picture.