Cart events
Every event name the mini-cart emits or listens for, and what each payload carries.
Cart events
All names are defined in src/entrypoints/mini-cart/internals/core.ts as the CartEvents constant. They are dispatched
as CustomEvent on window, so any script on the page can listen or dispatch without importing anything.
Payload types are in the CartEventDetailMap interface in the same file.
Regenerate this page
sed -n '/export const CartEvents/,/} as const/p' \
src/entrypoints/mini-cart/internals/core.tsListening for cart changes
cart:changed fires after every successful change of any kind and carries the authoritative cart from Shopify.
window.addEventListener('cart:changed', (e) => {
console.log(e.detail.cart.item_count, e.detail.reason);
});reason is one of add, change, update, clear or get.
cart:changed:debounced fires 250 milliseconds after the last change. Use it instead when rendering is expensive, so a
burst of quantity clicks produces one render.
Commands you can dispatch
Dispatching one of these makes the mini-cart perform the action, with the same queueing and stale-key recovery its own controls get.
| Event | Payload |
|---|---|
mini-cart:get | none |
mini-cart:add | AddToCartPayload |
mini-cart:change | ChangeLinePayload |
mini-cart:update | UpdateCartPayload |
mini-cart:clear | none |
window.dispatchEvent(
new CustomEvent('mini-cart:add', {
detail: { items: [{ id: 123456789, quantity: 1 }] },
}),
);Lifecycle events
Each action emits a start event, then either success or error.
| Event | Payload |
|---|---|
cart:add:start | AddToCartPayload |
cart:add:success | { payload, cart } |
cart:add:error | { payload, error } |
cart:change:start | ChangeLinePayload |
cart:change:success | { payload, cart } |
cart:change:error | { payload, error } |
cart:update:start | UpdateCartPayload |
cart:update:success | { payload, cart } |
cart:update:error | { payload, error } |
cart:clear:start | none |
cart:clear:success | { cart? } |
cart:clear:error | { error } |
cart:clear:success can arrive without a cart, because an interceptor can observe a clear it did not perform. Treat
cart as optional there.
Change events
| Event | Payload |
|---|---|
cart:changed | { cart, reason? } |
cart:changed:debounced | { cart, reason? } |
Request events
| Event | Payload |
|---|---|
cart:request | { endpoint, method, payload? } |
cart:response | { endpoint, method, cart } |
cart:error | { endpoint, method, error } |
Fetch interceptor events
These report raw fetch activity against cart URLs, including requests the mini-cart did not make.
| Event | Payload |
|---|---|
cart:fetch:request | { url, method, init? } |
cart:fetch:response | { url, method, status, data } |
cart:fetch:error | { url, method, error } |
Request and response emission is off by default, because other apps make a large number of cart requests and the noise
is not useful. Turn it on by constructing CartFetchInterceptor with { emitRequest: true, emitResponse: true }.
UI events
| Event | Payload | Direction |
|---|---|---|
mini-cart:ui:open | none | Ask the drawer to open |
mini-cart:ui:close | none | Ask the drawer to close |
mini-cart:ui:update | { action } | Ask for an arbitrary UI action |
mini-cart:ui:opened | none | The drawer has opened |
mini-cart:ui:closed | none | The drawer has closed |
open asks the drawer to open, and opened reports that it has. Listening to open when you meant opened runs your
code before the drawer is on screen.
Lifecycle marker
| Event | Payload |
|---|---|
mini-cart:ready | none |
mini-cart:ready fires once the root element has wired its subsystems. Code inside the drawer should use
parentMiniCart.execOnReady(...) rather than listening for this, because that handles the case where the element
connects after the root is already ready.
The X-Source header
CartService sends X-Source: mini-cart on every request it makes, and CartFetchInterceptor skips any response
carrying it.
Without that guard the interceptor would observe the mini-cart's own writes and emit every event twice. If you write code that calls the Ajax Cart directly and you want the drawer to notice, do not send the header. If you want to suppress the events, send it.
Related
Design and reasoning are in Mini-cart.