Woo Custom Events
Woo runtime events are browser CustomEvent objects. They bubble, so you can listen on a component, a nearby wrapper, or document.
Use events as the integration contract for work that happens after a Woo action. Do not use data-ome-state="success" as an integration contract; that state is visible UI feedback for the control that just finished an action.
Which Event Should I Use?
| Goal | Event |
|---|---|
| Open a mini-cart, track an add-to-cart conversion, or inspect the product that was added. | ome-woo:item-added |
| Refresh any cart-related integration after add, quantity update, or item removal. | ome-woo:cart-updated |
| Track add-to-cart failures. | ome-woo:add-to-cart-error |
| React to quantity changes or item removal with row-level detail. | ome-woo:item-quantity-updated or ome-woo:item-removed |
| React to committed variable-product selection state inside a Product Provider. | ome-woo:variation-selection-changed |
| Track checkout start, completion, and checkout errors. | ome-woo:checkout-started, ome-woo:checkout-complete, ome-woo:checkout-error |
ome-woo:item-added fires first for successful add-to-cart and includes product_id, quantity, and cart_summary. ome-woo:cart-updated follows when the integration only needs to know that the cart changed.
Event Summary
| Area | Event | Dispatch target | Detail payload |
|---|---|---|---|
| Cart boot | ome-woo:cart-loaded | First cart display root found, or document.body. | { cart_summary } |
| Product add | ome-woo:item-added | Standalone add button or submitted AddToCartForm. | { product_id, quantity, cart_summary } |
| Product add | ome-woo:cart-updated | Same target as the successful cart mutation. | { cart_summary } |
| Product add | ome-woo:add-to-cart-error | Standalone add button or submitted AddToCartForm. | { product_id, quantity, error } |
| Product selection | ome-woo:variation-selection-changed | Nearest ProductProvider root. | { product_id, selection, selected_variation, current_product } |
| Cart item mutation | ome-woo:item-quantity-updated | Cart item quantity input. | { key, quantity, cart_summary } |
| Cart item mutation | ome-woo:item-removed | Cart item remove button, or document.body if the button was detached first. | { key, cart_summary } |
| Cart item mutation | ome-woo:cart-error | Cart item quantity input or remove button. | { action, key, quantity?, error } |
| Checkout | ome-woo:checkout-loaded | Checkout provider, checkout form, checkout notices, or document.body. | { checkout } |
| Checkout | ome-woo:checkout-started | Checkout form. | {} |
| Checkout | ome-woo:checkout-complete | Checkout form. | { checkout } |
| Checkout | ome-woo:checkout-error | Checkout form. | { errors?, phase?, source?, error?, diagnostic? } |
Shared Payload Shapes
cart_summary is the live cart summary after the mutation:
type WooCartSummary = {
item_count: number;
line_count: number;
};
error is a safe Woo error summary:
type WooErrorSummary = {
code: string;
message: string;
status: number;
field_keys?: string[];
};
checkout is the current Store API checkout response. It can include fields such as order_id, status, order_key, payment_method, payment_result, and __experimentalCart.
diagnostic is present on payment adapter failures when the adapter can provide a safe diagnostic object. It can include methodId, adapterId, provider, paymentType, fieldMode, phase, code, message, details, and sequence.
Product Selection Event
ome-woo:variation-selection-changed
| Contract | Value |
|---|---|
| Dispatch target | The nearest OmeWooProductProvider root. Standalone AddToCartForm does not emit this event. |
| Bubbles | Yes. |
| Composed | Yes. |
| Cancelable | No. |
| When it fires | After Provider datasets and form mirrors have committed a new semantic variable-product selection state. Initialization emits only the final settled state. Recommitting the same state does not emit again. Simple products do not emit it. |
| Detail payload | { product_id, selection: { phase, attributes }, selected_variation, current_product } |
selection.phase is base, partial, resolved, or invalid. selected_variation is the complete resolved variation object or null. current_product is the complete base product until resolution succeeds, then the complete resolved variation. Availability remains a field of the product or variation object; it is not encoded in the phase.
document.addEventListener("ome-woo:variation-selection-changed", (event) => {
const detail = (event as CustomEvent).detail;
if (detail.selection.phase === "resolved") {
console.log(detail.selected_variation);
}
});
Product Add Events
ome-woo:item-added
| Contract | Value |
|---|---|
| Dispatch target | The standalone AddToCartButton, or the submitted AddToCartForm for form-submit buttons. |
| Bubbles | Yes. |
| When it fires | After Store API POST /cart/add-item succeeds and the runtime has a fresh cart summary. |
| Detail payload | { product_id, quantity, cart_summary: { item_count, line_count } } |
Use this event when the integration needs the product and quantity that were just added.
ome-woo:cart-updated
| Contract | Value |
|---|---|
| Dispatch target | The same element that dispatched the successful cart mutation event. |
| Bubbles | Yes. |
| When it fires | After add-to-cart, quantity update, or item removal succeeds. |
| Detail payload | { cart_summary: { item_count, line_count } } |
Use this event when the integration only needs the latest cart count or line count.
Cart mutation scheduling is intentionally not a public event stream. There is no generic transaction-lifecycle event. For local visual progress, style data-ome-woo-mutation-phase; for business integrations, keep using the semantic events above.
ome-woo:add-to-cart-error
| Contract | Value |
|---|---|
| Dispatch target | The standalone AddToCartButton, or the submitted AddToCartForm for form-submit buttons. |
| Bubbles | Yes. |
| When it fires | After Store API POST /cart/add-item fails. |
| Detail payload | { product_id, quantity, error: { code, message, status, field_keys? } } |
Cart Item Events
ome-woo:cart-loaded
| Contract | Value |
|---|---|
| Dispatch target | First matching cart display root: [data-ome-woo-cart-count], [data-ome-woo-cart-total-field], [data-ome-woo-cart-items], [data-ome-woo-cart-notices], or document.body. |
| Bubbles | Yes. |
| When it fires | After Woo cart boot loads and cart display components are bound. |
| Detail payload | { cart_summary: { item_count, line_count } } |
ome-woo:item-quantity-updated
| Contract | Value |
|---|---|
| Dispatch target | The cart item quantity input. |
| Bubbles | Yes. |
| When it fires | After each real Store API quantity response is committed. Debounced-away, cancelled, and already-satisfied no-op targets do not emit it. An intermediate response still emits this semantic event, while control-local success waits for the latest target. |
| Detail payload | { key, quantity, cart_summary: { item_count, line_count } } |
ome-woo:item-removed
| Contract | Value |
|---|---|
| Dispatch target | The cart item remove button. If that button was detached before the request finished, the event is dispatched from document.body. |
| Bubbles | Yes. |
| When it fires | After Store API POST /cart/remove-item succeeds. |
| Detail payload | { key, cart_summary: { item_count, line_count } } |
ome-woo:cart-error
| Contract | Value |
|---|---|
| Dispatch target | The cart item quantity input for quantity failures, or the remove button for removal failures. |
| Bubbles | Yes. |
| When it fires | After Store API quantity update or item removal fails. |
| Detail payload | { action, key, quantity?, error: { code, message, status, field_keys? } }, where action is "update-item" or "remove-item". |
Checkout Events
ome-woo:checkout-loaded
| Contract | Value |
|---|---|
| Dispatch target | First matching checkout root: [data-ome-woo-checkout-provider], form[data-ome-woo-checkout-form], [data-ome-woo-checkout-notices], or document.body. |
| Bubbles | Yes. |
| When it fires | After checkout boot loads and checkout components are bound. |
| Detail payload | { checkout } |
ome-woo:checkout-started
| Contract | Value |
|---|---|
| Dispatch target | The checkout form. |
| Bubbles | Yes. |
| When it fires | After local submit validation passes and before payment preparation or Store API checkout submission. |
| Detail payload | {} |
ome-woo:checkout-complete
| Contract | Value |
|---|---|
| Dispatch target | The checkout form. |
| Bubbles | Yes. |
| When it fires | After Store API checkout succeeds. Redirect handling can happen after this event. |
| Detail payload | { checkout } |
ome-woo:checkout-error
| Contract | Value |
|---|---|
| Dispatch target | The checkout form. |
| Bubbles | Yes. |
| When it fires | After local validation, payment preparation, payment result handling, or Store API checkout fails. |
| Detail payload | Local validation: { errors, phase, source: "local-validation" }. Runtime/payment failure: { error, diagnostic? }. |
errors is an array of checkout field errors:
type WooCheckoutFieldError = {
field_key: string;
code: "required" | "invalid_email" | "invalid_country" | "invalid_state";
message: string;
};
phase is "submit" or "update". source is currently "local-validation" when the checkout form blocks submission before Store API checkout.
Example: Open A Mini-Cart Drawer After Add To Cart
Author the drawer and trigger normally:
<OmeDrawerTrigger
targeting='{{"targetDrawerId":"store-mini-cart"}}'
content='{{"label":"Cart"}}'
/>
<OmeDrawer
identity='{{"drawerId":"store-mini-cart"}}'
settings='{{"direction":"right","dismissible":true}}'
>
{#slot default}
<OmeDrawerTitle>Shopping bag</OmeDrawerTitle>
<OmeWooCartItems>
{#slot default}
<OmeWooCartItemImage />
<OmeWooCartItemTitle />
<OmeWooCartItemQuantity />
<OmeWooCartItemRemove />
{/slot}
{#slot empty}
Your cart is empty.
{/slot}
</OmeWooCartItems>
<OmeWooCartTotalsList />
<OmeDrawerClose>Close</OmeDrawerClose>
{/slot}
</OmeDrawer>
Then click the real trigger when ome-woo:item-added bubbles:
document.addEventListener("ome-woo:item-added", () => {
const trigger = document.querySelector(
'[data-ome-drawer-trigger][data-ome-target-drawer-id="store-mini-cart"]',
);
if (trigger instanceof HTMLButtonElement) {
trigger.click();
}
});
This keeps OmeDrawerTrigger and OmeDrawer as the drawer owners. The Woo event only decides when to open it.
Example: Track Add-To-Cart Analytics
document.addEventListener("ome-woo:item-added", (event) => {
if (!(event instanceof CustomEvent)) {
return;
}
const { product_id, quantity, cart_summary } = event.detail;
window.dataLayer?.push({
event: "add_to_cart",
product_id,
quantity,
cart_items: cart_summary.item_count,
});
});
Use ome-woo:item-added here because analytics usually needs the specific product and quantity.
Example: Refresh Cart Integrations
document.addEventListener("ome-woo:cart-updated", (event) => {
if (!(event instanceof CustomEvent)) {
return;
}
const { cart_summary } = event.detail;
document.documentElement.dataset.cartItems = String(cart_summary.item_count);
});
Use ome-woo:cart-updated when the integration does not care whether the cart changed because of add, quantity, or removal.
Example: Capture Checkout Errors
document.addEventListener("ome-woo:checkout-error", (event) => {
if (!(event instanceof CustomEvent)) {
return;
}
const { errors, error, diagnostic } = event.detail;
console.warn("Checkout failed", {
fieldErrors: errors,
error,
diagnostic,
});
});
Use this for logging, support tooling, or checkout instrumentation. Let CheckoutNotices remain responsible for visible customer messages.