v157 · capabilities · the full flow, for real

Notification → popup lab

The explainer's webmail scenario, live: a service-worker notification whose click makes this already-open tab open a connected preview popup. Every stage below is the real API — real registration, real permission prompt, real notification, real client.postMessage(…, {delegate: 'popup'}) in the worker, and a real synchronous window.open() in this page's message handler. On a browser without the feature, that last call hits the popup blocker — which is precisely the gap being closed, and this lab shows it honestly.

To see the delegated success path you need a Chromium build with the CapabilityDelegationPopup flag — launch with --enable-experimental-web-platform-features (no released Chrome ships it; ChromeStatus milestone: none yet). Everywhere else, stages 1–5 still run for real and stage 6 reports the genuine popup-blocker outcome. Notifications also require this page to stay visible/focused when you click the notification.

The flow

  1. waiting1 · Register the service worker (../sw.js, feature scope)
  2. waiting2 · Notification permission
  3. waiting3 · Show the notification (then click it!)
  4. waiting4 · Worker receives notificationclick, focuses this tab, posts the message
  5. waiting5 · This page receives the message
  6. waiting6 · window.open() from the message handler
Experiment arms (edge cases from the explainer)

Nothing yet.

what the popup proves

The popup this lab opens is popup-target.html. It checks window.opener, synchronously reads a value this tab holds in memory (LAB_SHARED_STATE) and messages back — the state-sharing that Clients.openWindow()'s cold new context cannot give you, and the reason the explainer routes the open through the client tab instead of the worker.

see also