JavaScript events
Reign implements Shopify's Standard Storefront Events and Actions: the cross-theme interface that apps, analytics tools, and AI agents use to read and drive the storefront. You integrate against the standard once. It works on Reign without forking theme files, parsing markup, or intercepting network requests. The same code keeps working on any other theme that implements the standard.
Two Shopify references define the contract:
Anything you find in the theme source that is not a shopify: event or a Shopify.actions call is internal wiring. It can change at any time, so do not depend on it.
Listening for events
Every event bubbles to document. Add a listener and read the event properties:
document.addEventListener('shopify:cart:lines-update', (event) => {
console.log(event.action, event.lines); // "add", "update", or "remove"
event.promise?.then(({ cart }) => {
console.log(cart.totalQuantity, cart.cost.totalAmount.amount);
});
});
Events that describe an operation in progress (the cart mutations, variant selection, and the collection or search refresh) carry a promise. It resolves once the operation commits and gives you the canonical result: the updated cart, the selected variant, or the new product count. Read the promise when you need the final state rather than the optimistic one.
Events Reign emits
| Event | Fires when |
|---|---|
shopify:page:view |
every page load |
shopify:product:view |
a product page loads |
shopify:product:select |
the shopper changes a variant |
shopify:collection:view |
a collection page loads |
shopify:collection:update |
collection filters or sort change |
shopify:search:update |
search filters or sort change |
shopify:cart:view |
the cart drawer opens |
shopify:cart:lines-update |
a line is added, updated, or removed |
shopify:cart:note-update |
the cart note changes |
shopify:cart:discount-update |
a discount is applied or removed |
shopify:cart:error |
a cart operation fails |
Payloads follow the Shopify Storefront GraphQL API shape: camelCase fields, and prices as money objects with amount and currencyCode. The full payload for each event is documented in Shopify's standard events reference linked above.
Driving the cart
Shopify injects a Shopify.actions object on every storefront. Reign configures it so your calls render in Reign's own drawer and header, with no page reload.
// Add to cart. Updates Reign's drawer and header in place, no reload.
const { cart, userErrors } = await Shopify.actions.updateCart({
lines: [{ merchandiseId: 'gid://shopify/ProductVariant/123', quantity: 1 }],
});
await Shopify.actions.openCart(); // opens Reign's cart drawer
const { cart: current } = await Shopify.actions.getCart(); // reads the current cart
updateCart also emits the matching shopify:cart: events for you, so code that calls it does not need to dispatch them too. Always check userErrors before you use cart.
Common examples
Track add to cart in analytics
document.addEventListener('shopify:cart:lines-update', (event) => {
if (event.action !== 'add') return;
event.promise?.then(({ cart }) => {
myAnalytics.addToCart(cart);
});
});
Update the cart from your own code
await Shopify.actions.updateCart({
lines: [{ merchandiseId: 'gid://shopify/ProductVariant/123', quantity: 1 }],
});
// Reign re-renders its cart drawer and header. No extra refresh call needed.
React when a shopper picks a variant
document.addEventListener('shopify:product:select', (event) => {
event.promise?.then(({ variant }) => {
if (variant) updateBadge(variant.availableForSale);
});
});
Pause background media when the cart drawer opens
document.addEventListener('shopify:cart:view', () => {
video.pause();
});