Skip to content

Theme events overview

Note

This documentation is provided for developers looking to build on top of our theme. We assume advanced knowledge of JavaScript, CSS and Liquid. Please note that while we welcome feedback, we are not able to provide support for anything described here.

JavaScript theme events allow you to build on top of our themes in a predictable and reliable way.

The theme dispatches events at key points in its lifecycle, like when a product is added to the cart or when the current variant is changed. Theme events also provide relevant data directly from theme components.

Additionally, the theme listens to events that allow you to control theme elements, for example, refreshing all sections that show cart state.

Target

Events from the theme are dispatched to document.

Product root

The product root element is an element that contains the variant selectors and the product form. It is also the primary Alpine.js component for the product section.

The product root is identified by its [x-data] attribute but it also has a data-product-root attribute to make it easier to select. The value of the attribute is the section’s ID as generated by Shopify ({{ section.id }}).

HTML
<div
  id="shopify-section-template--14962412257369__main"
  class="shopify-section"
>
  <section
    id="template--14962412257369__main"
    x-data="Product({ /* … */ })"
    data-product-root="template--14962412257369__main"
  ></section>
</div>
<div
  id="shopify-section-template--14962412257369__main"
  class="shopify-section"
>
  <section
    id="template--14962412257369__main"
    x-data="Product({ /* … */ })"
    data-product-root="template--14962412257369__main"
  ></section>
</div>
JavaScript
const productRootEl = document.querySelector(
  `[data-product-root="${shopifySectionId}"]`
);

// or:

const productRootEl = document
  .querySelector(`.shopify-section-${shopifySectionId}`)
  .querySelector('[data-product-root]');

// or:

const productRootEl = productFormEl.closest(
  '[data-product-root]'
);

// etc.
const productRootEl = document.querySelector(
  `[data-product-root="${shopifySectionId}"]`
);

// or:

const productRootEl = document
  .querySelector(`.shopify-section-${shopifySectionId}`)
  .querySelector('[data-product-root]');

// or:

const productRootEl = productFormEl.closest(
  '[data-product-root]'
);

// etc.

Alpine.js

Our theme events can be listened to from Alpine.js as well as plain JavaScript. Here’s an example implementation of a theme:variant:change event listener in both JavaScript and Alpine.js.

JavaScript
JavaScript
document.addEventListener('theme:variant:change', (e) => {
  const {
    productRootEl,
    formEl,
    variant,
    previousVariant,
    product,
  } = e.detail;
});
document.addEventListener('theme:variant:change', (e) => {
  const {
    productRootEl,
    formEl,
    variant,
    previousVariant,
    product,
  } = e.detail;
});
Alpine.js
Liquid
<div
  x-data="{ variantId: null }"
  @theme:variant:change.document="variantId = $event.detail.variant.id"
>
  The variant ID is <span x-text="variantId"></span>
</div>
<div
  x-data="{ variantId: null }"
  @theme:variant:change.document="variantId = $event.detail.variant.id"
>
  The variant ID is <span x-text="variantId"></span>
</div>

Proxies

Sometimes, properties returned in detail objects can be JavaScript Proxies, because they are reactive properties from an Alpine.js data scope. While they should behave just like their underlying value in most cases, you can use Alpine.raw() to unwrap them should you need to, for example:

JavaScript
document.addEventListener('theme:variant:change', (e) => {
  console.log('Variant Proxy', e.detail.variant);
  console.log(
    'Unwrapped variant object',
    Alpine.raw(e.detail.variant)
  );
});
document.addEventListener('theme:variant:change', (e) => {
  console.log('Variant Proxy', e.detail.variant);
  console.log(
    'Unwrapped variant object',
    Alpine.raw(e.detail.variant)
  );
});

Logging theme events in the console

Theme events are logged to the console inside the theme editor. If you'd like to log events outside the theme editor, set window.themeEventsDebugMode to true before the theme-events.js script is evaluated.

Naming convention

Theme events start with theme:, for example theme:variant:change.

Note

Events that don’t start with theme: are internal and are subject to change at any time.

Control events

Control events dispatched to the theme take the form of a command, with a verb in the second slot.

Theme eventControl event
theme:variant:change is dispatched by the theme when the current variant has changedtheme:change:variant can be dispatched to the theme to change the current variant

Events list

Theme events

  • theme:variant:change
  • theme:product:add
  • theme:line-item:change
  • theme:cart:change
  • theme:cart:update
  • theme:cart-drawer:opening
  • theme:cart-drawer:open
  • theme:cart-drawer:closing
  • theme:cart-drawer:closed

Error events

  • theme:product:error:add-to-cart
  • theme:line-item:error
  • theme:cart:error:other
  • theme:cart:error

Control events

These are events that the theme listens to.

  • theme:change:variant
  • theme:update:cart
  • theme:open:cart-drawer
  • theme:close:cart-drawer

Theme support

You can check window.theme.events.version to see if a theme supports theme events.

ThemeTheme events support
ExhibitComing soon
Shapes v3.0.0v1.0
Baseline v3.1.0v1.0
CascadeComing soon
LabelComing soon