Skip to content

Show a retry overlay when the checkout window is blocked - #791

Merged
kyle-schellen merged 15 commits into
mainfrom
ks-web-blocked-popup-session
Oct 6, 2026
Merged

kyle-schellen merged 15 commits into
mainfrom
ks-web-blocked-popup-session

Conversation

@kyle-schellen

@kyle-schellen kyle-schellen commented Sep 18, 2026 •

Copy link
Copy Markdown
Contributor

What changes are you making?

Problem. When the browser blocks the checkout window (window.open returns null), the overlay still says "Continue your purchase in the checkout window". There is no window, the "checkout window" link does nothing, and the only way out is to close the overlay. Blocks usually happen because the host page does work (for example, creating a cart) between the buyer's click and open(), and browsers only allow a new window shortly after a click.

Change. The overlay now shows a blocked state: "Your browser blocked the checkout window." with Open checkout and Close. Open checkout calls window.open again from the buyer's own click, which browsers allow, so the common case recovers in one tap.

Situation Buyer sees Host page receives
Window blocked Blocked overlay Nothing yet
Open checkout, window opens Checkout window; overlay switches to its normal state start, then close when checkout ends
Open checkout, blocked again Blocked overlay stays Nothing yet
Blocked overlay closed (Close, Escape, close(), or a target change) Overlay hidden close
Overlay hidden by the host (display: none on the element or ::part(overlay)) Nothing Nothing

Other details:

  • Trying again never dispatches close, whether it's our Open checkout button, a store's own button in the overlay-blocked slot, or the store's code calling open() again.
  • Logs a warning at log-level="warn". blocked telemetry is now retryable: true, with isRetry: true when a retry is blocked again.
  • No changes to attributes, properties, methods, or events. The blocked copy sits in a new overlay-blocked slot next to the existing overlay slot, and data-state="blocked" on the dialog switches between them.
  • The overlay visibility check moved into #isDialogVisible() so both states share it.
  • The <dialog> element's native close listeners ignore the event if the dialog is open again. The native event fires asynchronously, and a retry closes and re-shows the dialog in the same task.

Not in this PR: accessible names for the overlay (both states).

How to test

  • dev web test and dev web lint. New tests cover the blocked overlay, the retry, and close when the blocked overlay is closed.
  • Sample app (pnpm sample): under Flow, choose Use existing checkout source and paste a cart permalink (https://your-store.myshopify.com/cart/<variant-id>:1). In the DevTools console, run setTimeout(() => document.querySelector('shopify-checkout').open(), 8000), then don't click or type on the page for 8 seconds (a click gives the page a fresh user activation, so the window would open). The browser blocks the window and the overlay shows the blocked state. Click Open checkout and checkout opens. Run it again and click Close to see close in the Events panel.
  • To see a retry that's blocked again, run window.open = () => null in the console first (reload to undo).

Before you merge

Important

  • I've added tests to support my implementation
  • I have read and agree with the Contribution Guidelines
  • I have read and agree with the Code of Conduct
  • I've updated the relevant platform README (platforms/web/README.md)
Screen.Recording.2026-09-28.at.11.40.53.AM.mov

@github-actions github-actions Bot added the #gsd:50662 Rebase Checkout Kit on UCP label Sep 18, 2026

Copy link
Copy Markdown
Contributor Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

@kyle-schellen kyle-schellen changed the title Fix blocked popup session state Show a retry overlay when the checkout window is blocked Sep 24, 2026
@kyle-schellen kyle-schellen self-assigned this Sep 24, 2026
@kyle-schellen
kyle-schellen force-pushed the ks-web-blocked-popup-session branch from f94ab3c to 7f31272 Compare September 25, 2026 17:42
@kyle-schellen
kyle-schellen marked this pull request as ready for review September 25, 2026 20:07
@kyle-schellen
kyle-schellen requested a review from a team as a code owner September 25, 2026 20:07
@github-actions

github-actions Bot commented Sep 25, 2026 •

Copy link
Copy Markdown

Web — Coverage Report

Lines Statements Branches Functions
Coverage: 97%
95.21% (398/418) 85.77% (211/246) 97.16% (103/106)

@github-actions

github-actions Bot commented Sep 25, 2026 •

Copy link
Copy Markdown

Bundle Size Budgets

Budget Size Limits Result
Web JavaScript (uncompressed) 33.93 KiB (+669 B) 35 KiB soft / 50 KiB hard ✅ Within budget

Bundle and package size

Web bundle sizes cover shipped runtime JavaScript. Package sizes cover the full published archive, including any source maps, declarations, and documentation it contains.

Platform Measurement Compression Base Head Delta
Web JavaScript bundle Uncompressed 33.3 KiB 33.9 KiB +669 B
Web JavaScript bundle gzip 10.2 KiB 10.5 KiB +287 B
Web npm package (.tgz) gzip 89.5 KiB 91.0 KiB +1.5 KiB
Web package files (uncompressed)

These are uncompressed file sizes; they do not sum to the compressed package size above.

File Base Head Delta
dist/index.js.map 249.0 KiB 251.0 KiB +2.0 KiB
dist/custom-elements.json 47.5 KiB 48.8 KiB +1.3 KiB
dist/index.d.ts 47.9 KiB 48.0 KiB +34 B
dist/index.js 33.3 KiB 33.9 KiB +669 B
README.md 20.2 KiB 20.8 KiB +581 B
package.json 3.6 KiB 3.6 KiB 0 B
LICENSE 1.1 KiB 1.1 KiB 0 B
How sizes are measured

Measured from the PR base SHA and PR head SHA. Web bundle rows sum shipped .js, .mjs, and .cjs files under dist/, excluding source maps and declarations. The gzip bundle size sums files compressed individually with gzip -n -9. npm package sizes are gzip-compressed .tgz archives; Android AAR sizes are ZIP archives. Package sizes are not final app binary sizes.

@kyle-schellen
kyle-schellen added this pull request to stack #837 September 28, 2026 13:15
Comment thread platforms/web/src/checkout.ts Outdated
<slot name="overlay-blocked">
<div class="overlay-content-wrapper">
<div class="overlay-content">
Your browser blocked the checkout window. <br />

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we should think about localisation at some point

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good callout. Web doesn't localize the overlay yet, and merchants can provide their own copy through the overlay and overlay-blocked slots, but localized defaults would be nice. I created an issue so we can keep it on our radar.

@markmur
markmur force-pushed the ks-web-blocked-popup-session branch from d38fe43 to 0001bae Compare October 6, 2026 11:05
Comment thread platforms/web/src/checkout.ts Outdated
<slot name="overlay-blocked">
<div class="overlay-content-wrapper">
<div class="overlay-content">
Your browser blocked the checkout window. <br />

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wondering if this wording is better

Suggested change
Your browser blocked the checkout window. <br />
Your browser blocked the checkout window from opening. <br />

@markmur
markmur force-pushed the ks-web-blocked-popup-session branch from 2930889 to a06777a Compare October 6, 2026 12:46
@kyle-schellen
kyle-schellen merged commit cbb9c1b into main Oct 6, 2026
23 checks passed
@kyle-schellen
kyle-schellen deleted the ks-web-blocked-popup-session branch October 6, 2026 13:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

#gsd:50662 Rebase Checkout Kit on UCP

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants