Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 19 additions & 7 deletions platforms/web/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,15 @@ Where the checkout is presented. Defaults to `"auto"`.
> the host page away. The component falls back to `"auto"` if you set one,
> and logs a warning at `log-level="warn"` or more verbose.

> [!NOTE]
> If the browser refuses to open the window (for example, a popup blocker, or
> `open()` called outside a user gesture), the component dispatches `blocked`
> and the [overlay scrim](#overlay-scrim) says so and offers a button to try
> again. Closing it dispatches `close`. If you hide the overlay, listen for
> `blocked` to show your own message, and call `open()` again from a user
> action such as a click. A call made directly from the listener is ignored.
> The component logs a warning at `log-level="warn"` or more verbose.

### `appearance`

Sets the checkout appearance preference. Defaults to `"storefront"`.
Expand Down Expand Up @@ -472,7 +481,9 @@ shopify-checkout {

While a popup is open the component renders a `<dialog>` scrim over the host
page, with a "Continue your purchase in the checkout window" link and a close
button. Hide it by either:
button. If the browser blocks the window, the scrim instead says "Your browser
blocked the checkout window." with an "Open checkout" button that tries again.
Hide it by either:

- Setting `display: none` on the element itself, or
- Targeting the `overlay` shadow part:
Expand All @@ -486,19 +497,20 @@ shopify-checkout::part(overlay) {
## Checkout lifecycle

The element dispatches typed `CustomEvent`s at every meaningful moment of the
checkout session. The `start`, `update`, `complete`, and `close` events bubble,
so you can listen anywhere in your DOM, including a single delegated listener
at `document` if you have many elements on the page. The `error` event does not
bubble; attach its listener directly to the checkout element. Event payloads
are available in `event.detail`.
checkout session. The `start`, `update`, `complete`, `close`, and `blocked`
events bubble, so you can listen anywhere in your DOM, including a single
delegated listener at `document` if you have many elements on the page. The
`error` event does not bubble; attach its listener directly to the checkout
element. Event payloads are available in `event.detail`.

| Event | `event.detail` | When it fires |
| ---------- | -------------- | ------------- |
| `start` | `{checkout}` | Checkout has loaded and is interactive. |
| `update` | `{checkout}` | A change to line items, fulfillment, totals, or checkout messages produces a different checkout snapshot. |
| `complete` | `{checkout}` | The buyer completed the order successfully. |
| `error` | `{error}` | Checkout reported a terminal error, exposed as `{code, message}`. The component closes automatically after this event. |
| `close` | _(none)_ | The open session ended through `close()`, overlay dismissal, or detection of a popup the buyer closed. |
| `close` | _(none)_ | The open session ended through `close()`, overlay dismissal, or detection of a popup the buyer closed. If the browser blocked the window, no `start` precedes it. |
| `blocked` | _(none)_ | The browser blocked the checkout window. Fires on every blocked attempt, whether or not the overlay is shown. |

`start`, `update`, and `complete` carry a Checkout Kit `Checkout` snapshot in
`event.detail.checkout`. It preserves checkout data, including unknown
Expand Down
2 changes: 1 addition & 1 deletion platforms/web/sample/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ You can also choose **Use existing checkout source** in Settings. In that mode,

- **Settings** — persisted storefront domain, flow, target (`popup` | `auto`), appearance (default `storefront` | `app:light` | `app:dark` | `app:automatic` | `storefront`), and log-level (`debug` | `warn` | `error` | `none`) settings. The storefront domain appears first because the cart builder cannot load products without it.
- **Center workspace** — build mode shows a storefront-style product grid plus sticky cart banner; manual mode shows a focused checkout URL/cart permalink input.
- **Runtime** — shows component state above the `start`, `update`, `complete`, `error`, and `close` event log. Each entry includes the event detail and a JSON snapshot of component state at fire time.
- **Runtime** — shows component state above the `start`, `update`, `complete`, `error`, `close`, and `blocked` event log. Each entry includes the event detail and a JSON snapshot of component state at fire time.

The element is mounted on `<body>`. For `popup` / `auto`, the visible UI is mostly the overlay scrim while checkout is open in a separate window or tab.

Expand Down
2 changes: 1 addition & 1 deletion platforms/web/sample/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import {
} from "./storage";
import "./styles.css";

const EVENT_TYPES = ["start", "update", "complete", "close", "error"] as const;
const EVENT_TYPES = ["start", "update", "complete", "close", "error", "blocked"] as const;

const refs = queryRefs();

Expand Down
9 changes: 9 additions & 0 deletions platforms/web/src/checkout-events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,14 @@ export class ShopifyCheckoutCloseEvent extends CustomEvent<undefined> {
}
}

export class ShopifyCheckoutBlockedEvent extends CustomEvent<undefined> {
declare type: "blocked";

constructor() {
super("blocked", { bubbles: true });
}
}

export class ShopifyCheckoutErrorEvent extends CustomEvent<ShopifyCheckoutErrorEventDetail> {
declare type: "error";

Expand All @@ -64,4 +72,5 @@ export interface ShopifyCheckoutEventMap {
complete: ShopifyCheckoutCompleteEvent;
error: ShopifyCheckoutErrorEvent;
close: ShopifyCheckoutCloseEvent;
blocked: ShopifyCheckoutBlockedEvent;
}
Loading
Loading