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