Picture-in-Picture

Display a floating video using the Picture-in-Picture API - visible even when the browser is minimized. Works well with SpeakerLayout where the spotlight switches between dominant speakers.

Best Practices

  • Check document.pictureInPictureEnabled before showing the PiP button.
  • Handle both enterpictureinpicture and leavepictureinpicture events to sync state.

Some browsers also support the more flexible Document Picture-in-Picture API.

Define custom ParticipantViewUI

Add a button to toggle picture-in-picture mode:

import { useEffect } from "react";
import { useParticipantViewContext } from "@stream-io/video-react-sdk";

const CustomParticipantViewUI = () => {
  const { videoElement } = useParticipantViewContext();
  const [pictureInPictureElement, setPictureInPictureElement] = useState(
    document.pictureInPictureElement,
  );

  useEffect(() => {
    if (!videoElement) return;

    // sync local state
    const handlePictureInPicture = () => {
      setPictureInPictureElement(document.pictureInPictureElement);
    };

    videoElement.addEventListener(
      "enterpictureinpicture",
      handlePictureInPicture,
    );
    videoElement.addEventListener(
      "leavepictureinpicture",
      handlePictureInPicture,
    );

    return () => {
      videoElement.removeEventListener(
        "enterpictureinpicture",
        handlePictureInPicture,
      );
      videoElement.removeEventListener(
        "leavepictureinpicture",
        handlePictureInPicture,
      );
    };
  }, [videoElement]);

  const togglePictureInPicture = () => {
    if (videoElement && pictureInPictureElement !== videoElement)
      return videoElement.requestPictureInPicture().catch(console.error);

    document.exitPictureInPicture().catch(console.error);
  };

  return (
    <>
      <button
        disabled={!document.pictureInPictureEnabled}
        style={{ position: "absolute", top: 10, right: 10 }}
        onClick={togglePictureInPicture}
      >
        {pictureInPictureElement === videoElement ? "Leave" : "Enter"}{" "}
        picture-in-picture
      </button>
      {/* your other custom UI elements */}
    </>
  );
};

Final steps

Pass this custom ParticipantViewUI to layout components or ParticipantView as described in the ParticipantView customizations guide.