<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Coder Legion - Recent posts tagged pictureinpicture</title>
<link>https://coderlegion.com/tag/pictureinpicture</link>
<description>Powered by Question2Answer</description>
<item>
<title>Beyond Video: Portal Any React Component into Picture-in-Picture with usePip</title>
<link>https://coderlegion.com/25261/beyond-video-portal-any-react-component-into-picture-in-picture-with-usepip</link>
<description>&lt;p&gt;Picture-in-Picture (PiP) has historically been limited to video elements. If you wanted to build a floating music player, a persistent chat widget, or an interactive pomodoro timer that stayed on top of other windows, you were out of luck. &lt;/p&gt;
&lt;p&gt;That changes with the browser's new &lt;strong&gt;Document Picture-in-Picture API&lt;/strong&gt;, which allows opening a floating window containing &lt;em&gt;arbitrary&lt;/em&gt; HTML content. However, managing this window's lifecycle, rendering React components inside it, and ensuring your CSS styles copy over correctly is a complex task.&lt;/p&gt;
&lt;p&gt;To solve this, the latest update to &lt;code&gt;react-hook-lab&lt;/code&gt; introduces the &lt;code&gt;usePip&lt;/code&gt; hook. This hook makes managing the Document Picture-in-Picture API completely seamless by handling state, managing portal containers, and cloning your stylesheets automatically.&lt;/p&gt;
&lt;h4 id=&quot;why-usepip-&quot;&gt;Why usePip?&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Declarative Portals&lt;/strong&gt;: Render any React component inside the floating window using a simple &lt;code&gt;&amp;lt;Pip&amp;gt;&lt;/code&gt; component.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Style Inheritance&lt;/strong&gt;: Automatically clones all stylesheets (including Tailwind or CSS-in-JS rules) from your main document into the PiP window.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Browser Fallback&lt;/strong&gt;: Gracefully detects support with &lt;code&gt;isSupported&lt;/code&gt; so you can show fallback UI on unsupported browsers.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h4 id=&quot;example-1-creating-an-interactive-floating-counter&quot;&gt;Example 1: Creating an Interactive Floating Counter&lt;/h4&gt;
&lt;p&gt;This simple example shows how easily you can open a PiP window and interact with React state from inside the floating layout.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;import React, { useState } from &quot;react&quot;;
import { usePip } from &quot;react-hook-lab&quot;;

export function FloatingCounter() {
  const { isSupported, isOpen, openPip, closePip, Pip } = usePip();
  const [count, setCount] = useState(0);

  if (!isSupported) {
    return &amp;lt;p&amp;gt;Document Picture-in-Picture is not supported in this browser.&amp;lt;/p&amp;gt;;
  }

  return (
    &amp;lt;div style={{ padding: &quot;20px&quot;, border: &quot;1px solid #ccc&quot;, borderRadius: &quot;8px&quot; }}&amp;gt;
      &amp;lt;h3&amp;gt;Interactive Counter Demo&amp;lt;/h3&amp;gt;
      &amp;lt;p&amp;gt;Main Window Count: {count}&amp;lt;/p&amp;gt;
      
      &amp;lt;button onClick={() =&amp;gt; (isOpen ? closePip() : openPip({ width: 300, height: 250 }))}&amp;gt;
        {isOpen ? &quot;Close Floating Window&quot; : &quot;Pop Out Counter&quot;}
      &amp;lt;/button&amp;gt;

      &amp;lt;Pip width={300} height={250}&amp;gt;
        &amp;lt;div style={{ padding: &quot;20px&quot;, textAlign: &quot;center&quot;, fontFamily: &quot;sans-serif&quot; }}&amp;gt;
          &amp;lt;h4&amp;gt;Floating Controller&amp;lt;/h4&amp;gt;
          &amp;lt;p style={{ fontSize: &quot;24px&quot;, fontWeight: &quot;bold&quot; }}&amp;gt;{count}&amp;lt;/p&amp;gt;
          &amp;lt;button onClick={() =&amp;gt; setCount((c) =&amp;gt; c + 1)} style={{ marginRight: &quot;8px&quot; }}&amp;gt;
            Increment
          &amp;lt;/button&amp;gt;
          &amp;lt;button onClick={() =&amp;gt; setCount((c) =&amp;gt; c - 1)}&amp;gt;
            Decrement
          &amp;lt;/button&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/Pip&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h4 id=&quot;example-2-building-a-floating-pomodoro-timer&quot;&gt;Example 2: Building a Floating Pomodoro Timer&lt;/h4&gt;
&lt;p&gt;Here is a more practical case study: an interactive Pomodoro timer that users can keep pinned to the corner of their screen while working in other apps.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;import React, { useState, useEffect } from &quot;react&quot;;
import { usePip } from &quot;react-hook-lab&quot;;

export function PomodoroTimer() {
  const { isOpen, openPip, closePip, Pip } = usePip();
  const [seconds, setSeconds] = useState(1500); // 25 minutes
  const [isActive, setIsActive] = useState(false);

  useEffect(() =&amp;gt; {
    let interval: any = null;
    if (isActive &amp;amp;&amp;amp; seconds &amp;gt; 0) {
      interval = setInterval(() =&amp;gt; setSeconds((s) =&amp;gt; s - 1), 1000);
    } else {
      clearInterval(interval);
    }
    return () =&amp;gt; clearInterval(interval);
  }, [isActive, seconds]);

  const formatTime = (totalSecs: number) =&amp;gt; {
    const mins = Math.floor(totalSecs / 60).toString().padStart(2, &quot;0&quot;);
    const secs = (totalSecs % 60).toString().padStart(2, &quot;0&quot;);
    return `${mins}:${secs}`;
  };

  return (
    &amp;lt;div style={{ padding: &quot;20px&quot;, maxWidth: &quot;400px&quot;, margin: &quot;auto&quot; }}&amp;gt;
      &amp;lt;h2&amp;gt;Pomodoro Timer&amp;lt;/h2&amp;gt;
      &amp;lt;p&amp;gt;Time remaining: {formatTime(seconds)}&amp;lt;/p&amp;gt;
      
      &amp;lt;button onClick={() =&amp;gt; (isOpen ? closePip() : openPip({ width: 280, height: 220 }))}&amp;gt;
        {isOpen ? &quot;Disable Floating mode&quot; : &quot;Go Floating&quot;}
      &amp;lt;/button&amp;gt;

      &amp;lt;Pip width={280} height={220}&amp;gt;
        &amp;lt;div style={{
          padding: &quot;16px&quot;,
          fontFamily: &quot;sans-serif&quot;,
          background: &quot;#1e293b&quot;,
          color: &quot;#ffffff&quot;,
          height: &quot;100%&quot;,
          boxSizing: &quot;border-box&quot;
        }}&amp;gt;
          &amp;lt;h3 style={{ margin: &quot;0 0 10px 0&quot; }}&amp;gt;Focus Mode&amp;lt;/h3&amp;gt;
          &amp;lt;div style={{ fontSize: &quot;36px&quot;, margin: &quot;10px 0&quot; }}&amp;gt;{formatTime(seconds)}&amp;lt;/div&amp;gt;
          &amp;lt;button onClick={() =&amp;gt; setIsActive(!isActive)} style={{ padding: &quot;6px 12px&quot;, marginRight: &quot;8px&quot; }}&amp;gt;
            {isActive ? &quot;Pause&quot; : &quot;Start&quot;}
          &amp;lt;/button&amp;gt;
          &amp;lt;button onClick={() =&amp;gt; { setSeconds(1500); setIsActive(false); }} style={{ padding: &quot;6px 12px&quot; }}&amp;gt;
            Reset
          &amp;lt;/button&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/Pip&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;how-it-works-behind-the-scenes&quot;&gt;How It Works Behind the Scenes&lt;/h4&gt;
&lt;p&gt;When you call &lt;code&gt;openPip()&lt;/code&gt;, the hook requests a new PiP window using &lt;code&gt;window.documentPictureInPicture.requestWindow()&lt;/code&gt;. Once created, it dynamically clones every CSS stylesheet registered on the main window into the header of the new window, ensuring consistent typography and style formatting. Finally, using React's &lt;code&gt;createPortal&lt;/code&gt;, it renders your custom markup directly inside the external floating window context.&lt;/p&gt;
&lt;h4 id=&quot;resources&quot;&gt;Resources&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;GitHub Repository&lt;/strong&gt;: &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/Saurav-TB-Pandey/react-hook-lab&quot;&gt;react-hook-lab&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;NPM Package&lt;/strong&gt;: &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.npmjs.com/package/react-hook-lab&quot;&gt;react-hook-lab&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LinkedIn Profile&lt;/strong&gt;: &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.linkedin.com/in/pandeysaurav/&quot;&gt;Saurav Pandey&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Originally published on my blog. You can &lt;a rel=&quot;nofollow&quot; href=&quot;https://sauravtbpandey.blogspot.com/2026/08/building-truly-floating-react.html&quot;&gt;read the alternative breakdown here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Originally published on my blog. You can &lt;a rel=&quot;nofollow&quot; href=&quot;https://dev.to/saurav_tb_pandey/beyond-video-portal-any-react-component-into-picture-in-picture-with-usepip-476m&quot;&gt;read the alternative breakdown here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/25261/beyond-video-portal-any-react-component-into-picture-in-picture-with-usepip</guid>
<pubDate>Tue, 08 Sep 2026 12:46:51 +0000</pubDate>
</item>
</channel>
</rss>