You can toggle picture in picture mode on any video element using the new webkitSetPresentationMode method on the video element.

This is currently supported in Mac OSX Catalina, and is soon coming to Mobile Safari with the release of iOS 14.

PiP Demo

Here’s a working version which sniffs for support via webkitSupportsPresentationMode and toggles picture in picture mode.

If the button is grayed out, your browser does not support webkitSetPresentationMode

Picture in Picture Code sample with React Hooks

Here is an example of loading a video, and attaching the relative events to a PiP button.

import React, { useEffect, useState, useRef } from "react";

const PIPDemo = () => {
  const video = useRef(null);
  const [pip, enablePip] = useState(false);
  const MODE_PIP = "picture-in-picture";
  const MODE_INLINE = "inline";

  useEffect(() => {
    // detect out if the browser supports PresentationMode
    const supportsPiP = (videoEl) => {
      return (
        videoEl &&
        videoEl.webkitSupportsPresentationMode &&
        typeof videoEl.webkitSetPresentationMode === "function"
      );
    };
    // set pip state
    enablePip(supportsPiP(video.current));
  }, [video]);

  const togglePiP = () => {
    const { current: v } = video;
    if (!pip) return;
    // switch between the 2 modes
    v.webkitSetPresentationMode(
      v.webkitPresentationMode === MODE_PIP ? MODE_INLINE : MODE_PIP,
    );
  };

  return (
    <div>
      <video
        ref={video}
        id="video"
        src="https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"
        controls
      />
      <div id="controls">
        <button type="button" onClick={() => video.current.play()}>
          Play
        </button>
        <button type="button" onClick={() => video.current.pause()}>
          Pause
        </button>
        <button type="button" onClick={() => togglePiP()} disabled={!pip}>
          Picture in Picture
        </button>
      </div>
    </div>
  );
};

References