Implementing a Cross-Page Playback Queue with Document Picture-in-Picture
The article explains how Bilibili leveraged Chrome’s Document Picture‑in‑Picture API to create a cross‑page playback queue displayed in a small always‑on‑top window, detailing style synchronization, independent lifecycle handling via a helper class, and real‑time updates using BroadcastChannel‑plus‑iframe messaging while relying solely on native web features.
In August 2023 Chrome 116 introduced the Document Picture-in-Picture (documentPictureInPicture) API. Bilibili used this feature to build a cross‑page playback queue that appears as a small always‑on‑top window on the homepage.
Document Picture-in-Picture differs from video PiP in that it can host arbitrary document content created via documentPictureInPicture.window . It can only be opened by a user gesture and the parent page must be loaded over HTTPS.
Main commands (code):
// In the parent page
documentPictureInPicture.window // reference to the pip window, null if not opened
documentPictureInPicture.requestWindow({ width: 200, height: 200, disallowReturnToOpener: false }) // open
documentPictureInPicture.window.close() // close
documentPictureInPicture.onenter = (event) => { const pipWindow = event.window; } // listener 1
documentPictureInPicture.addEventListener("enter", (event) => { const pipWindow = event.window; }) // listener 2
documentPictureInPicture.window.addEventListener("pagehide", () => {})Basic “Hello World!” example:
window.documentPictureInPicture.requestWindow()
documentPictureInPicture.window.append('Hello World!')The implementation initially used the same Vue3+TS stack as the Bilibili homepage. Two major problems were encountered:
Synchronising component styles between the parent page and the pip window.
Managing the lifecycle of the pip window so that multiple business modules do not interfere with each other.
Style synchronisation is performed by creating a link element that points to the bundled CSS file and appending it to the pip window’s head :
const link = document.createElement('link');
link.href = `https://path/to/pip.css`;
documentPictureInPicture.window.document.head.appendChild(link);To avoid interference between different features that may open a pip window, a helper class BiliDocPip was created. Each instance tracks its own open state and registers a pagehide listener on its own pip window:
class BiliDocPip {
_isopen = false;
get pipWindow() { return this._isopen ? window.documentPictureInPicture.window : null; }
async open() {
if (this._isopen) return true;
let curPipWindow = null;
try { curPipWindow = await window.documentPictureInPicture.requestWindow(); } catch(e) {}
if (!curPipWindow) return false;
this._isopen = true;
this.pipWindow.addEventListener('pagehide', () => { this._isopen = false; });
return true;
}
async close() { if (!this._isopen) return false; this.pipWindow?.close?.(); return true; }
}Cross‑page queue updates are propagated using a BroadcastChannel‑plus‑iframe scheme. Each page that participates in the queue injects a hidden iframe; the iframe forwards messages via postMessage to other iframes and finally to their parent pages, achieving real‑time synchronization across different domains.
Because the pip window shares the same storage (cookies, localStorage ) with the parent page, API calls that require a referer header succeed, while the referer itself is empty inside the pip window (e.g., location.href returns about:blank ).
Other native web features used in the project include:
Popover API for tooltip‑like UI.
Element.scrollIntoView with smooth options for list navigation.
CSS Nesting for cleaner style sheets.
Web Components (custom elements) and Lit for encapsulated, reactive UI components.
The final solution relies entirely on native browser capabilities, avoiding third‑party libraries and keeping the bundle size minimal.
Conclusion: Document Picture-in-Picture opens new possibilities for cross‑window interactions in web applications. By combining it with Web Components, Lit, and native communication APIs, developers can build sophisticated features such as the Bilibili cross‑page playback queue while maintaining performance and compatibility.
Bilibili Tech
Provides introductions and tutorials on Bilibili-related technologies.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.