---
title: "Theme events"

doc_type: static
doc_category: static
doc_version: v20270301
source_url:
  html: 'https://developer.shopline.com/docs/online-store-3-0-themes/best-practice/theme-events'
  md: 'https://developer.shopline.com/docs/online-store-3-0-themes/best-practice/theme-events.md'
---
# Theme events
Theme events serve as a communication mechanism between theme modules, or between theme modules and apps. Using standard events constructed via the [event constructor](#w6FWs) and APIs provided by the [event bus](#MFUoM), you can trigger or receive theme events applicable to specific scenarios within theme modules or apps.


## Event bus{#MFUoM}
The event bus acts as the central hub for information transmission. You can use the event bus to publish or subscribe to the theme events. The bus is responsible for notifying event subscribers, facilitating effective decoupling of modules, and enhancing system maintainability and scalability. 

A global event bus is injected into the `window` object under the [standard theme](https://developer.shopline.com/docs/online-store-3-0-themes/bottle.md), accessible through `window.themeEventCenter`.


### APIs{#wuYEA}
The event bus provides several APIs for easily publishing and subscribing to events.

<h4 id="cyeAk"></h4>
#### dispatch
This API triggers a specific event.

**Syntax**:`.dispatch(event: ThemeEvent): void`

<h5 id="EkJr4"></h5>
##### Properties
| **Property** | **Type** | **Required or not** | **Description** |
| --- | --- | --- | --- |
| event | ThemeEvent | Yes | The object instance of the theme event to be triggered. You can create a custom event object instance or a [standard event](#OlpLz) object instance.  |


<h5 id="ZLxYR"></h5>
##### Returns
None

<h5 id="dV1jV"></h5>
##### Example
The following example shows triggering a [Product viewed](#OgkPO) event through the event bus.

```javascript
window.themeEventCenter.dispatch(
  new ThemeEvent('product:viewed', {
    detail: {
      productId: '16069825781843611825520845',
      productHandle: 'Shirt',
      variantId: '18066825256105052042503900',
      price: 9999,
      currency: 'USD'
    }
  })
);
```

<h4 id="nqViy"></h4>
#### addListener 
This API listens to a specific event.

**Syntax**: `.addListener(eventName: string, callback: (event: Event) => void): EventListener`

<h5 id="CXPNS"></h5>
##### Properties 
| **Property** | **Type** | **Required or not** | **Description** |
| --- | --- | --- | --- |
| eventName | string | Yes | The name of the theme event to listen for. It can be a custom event name or a [standard event](#OlpLz) name. |
| callback | func | Yes | A function that executes when the event is triggered. It usually accepts the `event` parameter, allowing access to event object data through `event.detail`.<br/>For the specific data structure of `event.detail`, refer to [Create an event object](#ZMJbs).  |


<h5 id="ReE3Z"></h5>
##### Returns 
An `EventListener` object contains the following fields: 

| **Property** | **Type** | **Description** |
| --- | --- | --- |
| eventName | string | The name of the theme event being listened to. |
| remove | func | The method to remove the event listener.   |


<h5 id="UzZRY"></h5>
##### Example
The following example shows listening to a [Product viewed](#OgkPO) event through the event bus.

```javascript
window.themeEventCenter.addListener('product:viewed', (event) => {
  console.log(event.id);
  console.log(event.target);
  console.log(event.detail.productId);
});
```

<h4 id="jO4N0"></h4>
#### getCurrentDetail
This API retrieves the `detail` data from the most recent trigger of a specific event.

**Syntax**: `.getCurrentDetail(eventName: string): Record<string, any> | undefined`

<h5 id="XXSRl"></h5>
##### Properties
| **Property** | **Type** | **Required or not** | **Description** |
| --- | --- | --- | --- |
| eventName | string | Yes | The name of the theme event. It can be a custom event name or a [standard event](#OlpLz) name. |


<h5 id="GozJs"></h5>
##### Returns 
The `detail` data of the corresponding theme event. For the specific data structure of `event.detail`, refer to [Create an event object](#ZMJbs). 

<h5 id="RYZ45"></h5>
##### Example
The following example shows getting product data after the [Product viewed](#OgkPO) event is triggered through the event bus.

```javascript
const viewProduct = window.themeEventCenter.getCurrentDetail('product:viewed');

console.log(viewProduct?.productId); // Outputs the product ID
```


## Event constructor{#w6FWs}
The event constructor is a tool for creating event objects, defining event types, carrying data, and related properties. You can flexibly configure events, assigning them specific behaviors and characteristics for different scenarios, facilitating triggering and transmission.

Standard themes inject an event constructor into the `window` object, accessible via `window.ThemeEvent`. 


### Create an event object{#ZMJbs}
You can use `new ThemeEvent` to create an event object.

**Syntax**: `new ThemeEvent(eventName: string, eventInitDict: EventInit)`

<h4 id="QOArM"></h4>
#### Properties

<table>
<tr>
  <th>
    Property
  </th>
  <th>
    Type
  </th>
  <th>
    Required or not
  </th>
    <th>
    Description
    </th>
</tr>
<tr>
  <td>
eventName
  </td>
  <td>
 string
  </td>
  <td>
yes
  </td>
    <td>
        The name of the theme event.
    </td>
</tr>
<tr>
  <td>
  eventInitDict
  </td>
  <td>
EventInit
  
  </td>
    <td>
        Yes
    </td>
   
<td>
    The initialization data of the event. `EventInit` includes the following properties:<br/>
    - **`id`** (optional): Explicitly declare a unique identifier for the event, which will be passed to the [event listener](#nqViy). If not provided, a unique identifier will be automatically generated.<br/>
    - **`target`** (optional): Explicitly declare the source DOM node that triggers the event.<br/>
    - **`detail`** (required): The relevant data carried by the event, which the event listener can access through `Event.detail`.
    
**Standard data example:**
    ```typescript 
    interface EventInit {   
      id?: string;   
      target?: Element; 
      detail: Record<string, any> 
    } 
    ```  
  </td>

</tr>
</table>


<h4 id="pzmFW"></h4>
#### Returns
The event object `ThemeEvent`. 

<h5 id="OsbSq"></h5>
##### Example
The following example shows creating a [Product viewed](#OgkPO) event.

```javascript
new ThemeEvent('product:view', {
  detail: {
    ...
  }
});
```


### Standard events{#OlpLz}
The event constructor supports the following types of standard events:

<h4 id="OgkPO"></h4>
#### Product viewed
+ **Event name**: `product:viewed`
+ **Trigger timing**: This event is triggered when a customer enters a product detail page, opens a quick add-to-cart popup, or a single product component is displayed.

<h5 id="xa1h0"></h5>
##### Standard data
```typescript
interface Detail {
  productId: string;        // Product ID
  productHandle: string;    // Product handle
  variantId?: string;       // Product SKU ID. If the theme configuration does not have a default SKU selected, this will return an empty value.
  price?: number;           // Product SKU price. If the theme configuration does not have a default SKU selected, this will return an empty value.
  currency: string;         // Settlement currency 
}
```
<h5 id="tJPuA"></h5>
##### Example:
```javascript
// Triggering the event
window.themeEventCenter.dispatch(
  new ThemeEvent('product:viewed', {
    detail: {
      productId: '16069825781843611825520845',
      productHandle: 'Shirt',
      variantId: '18066825256105052042503900',
      price: 9999,
      currency: 'USD'
    }
  })
);

// Listening for the event
window.themeEventCenter.addListener('product:viewed', (event) => {
  console.log(event.detail.productId); // Outputs the product ID
});
```

<h4 id="l98H1"></h4>
#### Product SKU changed
+ **Event name**: `variant:changed`
+ **Trigger timing**: Triggered when switching SKUs on the product detail page, quick add-to-cart popup, or single product component.

<h5 id="Egirn"></h5>
##### Standard data
```typescript
interface Detail {
  productId: string;        // Product ID
  productHandle: string;    // Product handle
  variantId: string;        // Product SKU ID
  quantity: number;         // Product SKU quantity
  price: number;            // Product SKU price
  currency: string;         // Settlement currency 
}
```

<h5 id="Pst28"></h5>
##### Example
```javascript
// Triggering the event
window.themeEventCenter.dispatch(
  new ThemeEvent('variant:changed', {
    detail: {
      productId: '16069825781843611825520845',
      productHandle: 'Shirt',
      variantId: '18066825256105052042503900',
      quantity: 1,
      price: 9999,
      currency: 'USD'
    }
  })
);

// Listening for the event
window.themeEventCenter.addListener('variant:changed', (event) => {
  console.log(event.detail.variantId); // Outputs product SKU ID
});
```

<h4 id="VoAMO"></h4>
#### Product SKU added to the cart
+ **Event Name**: `variant:added`
+ **Trigger timing**: Triggered when adding a product to the cart. 

<h5 id="L65jg"></h5>
##### Standard data
```typescript
interface Detail {
  lineItemKey: string;    // Cart item identifier
  productId: string;      // Product ID
  productHandle: string;  // Product handle
  variantId: string;      // Product SKU ID
  quantity: number;       // Product SKU quantity
  price: number;          // Product SKU price. If the theme configuration does not have a default SKU selected, this will return an empty value.
  currency: string;       // Settlement currency
}
```

<h5 id="oMNND"></h5>
##### Example

```javascript
// Triggering the event
window.themeEventCenter.dispatch(
  new ThemeEvent('variant:added', {
    detail: {
      productId: '16069825781843611825520845',
      productHandle: 'Shirt',
      variantId: '18066825256105052042503900',
      quantity: 1,
      price: 9999,
      currency: 'USD',
      lineItemKey: '18064578594821059446022470:430512ac683d4903983eeee3c168ade8'
    }
  })
);

// Listening for the event
window.themeEventCenter.addListener('variant:added', (event) => {
  // Outputs product SKU ID and quantity
  console.log(event.detail.variantId, event.detail.quantity);
});
```

<h4 id="lcgwC"></h4>
#### Cart opened
+ **Event name**: `cart:opened`
+ **Trigger timing**: Triggered when the cart is opened.

<h5 id="OlkUE"></h5>
##### Standard data
```typescript
interface Detail {
  type: 'notification' | 'drawer';  // Cart type
}
```

<h5 id="esn0U"></h5>
##### Example
```javascript
// Triggering the event
window.themeEventCenter.dispatch(
  new ThemeEvent('cart:opened', {
    detail: {
      type: 'drawer'
    }
  })
);

// Listening for the event
window.themeEventCenter.addListener('cart:opened', (event) => {
  const { detail } = event;
  console.log('Cart opened', detail.type);
});
```

<h4 id="NUEBE"></h4>
#### Cart closed
+ **Event name**: `cart:closed`
+ **Trigger timing**: Triggered when the cart is closed.

<h5 id="D0Nvc"></h5>
##### Standard data
```typescript
interface Detail {
  type: 'notification' | 'drawer';  // Cart type
}
```

<h5 id="TtJit"></h5>
##### Example
```javascript
// Triggering the event
window.themeEventCenter.dispatch(
  new ThemeEvent('cart:closed', {
    detail: {
      type: 'drawer'
    }
  })
);

// Listening for the event
window.themeEventCenter.addListener('cart:closed', (event) => {
  const { detail } = event;
  console.log('Cart closed', detail.type);
});
```

<h4 id="yNnJg"></h4>
#### Open the cart
+ **Event name**: `cart:open` 
+ **Trigger timing**: Triggered when the action to open the cart is initiated. The caller does not need to concern themselves with theme configurations or implementations, as these are handled by the theme itself.

<h5 id="IGj3B"></h5>
##### Standard data
```typescript
interface Detail {
  refresh?: boolean; // Whether to refresh the cart contents, defaults to false
}
```

<h5 id="YRjnm"></h5>
##### Example
```javascript
// The "open cart" event is triggered
window.themeEventCenter.dispatch(
  new ThemeEvent('cart:open', {
    detail: {
      refresh: true	// Refresh the cart
    }
  })
);

// Listens for the "open cart" event and implements specific business logic
window.themeEventCenter.addListener('cart:open', (event) => {
  // Retrieve the passed parameters
  const { refresh } = event.detail;
  
  // Retrieve data of the recently added product
  const addedVariantDetail = themeEventCenter.getCurrentDetail('variant:added');

  // Outputs the product ID
  console.log(addedVariantDetail.productId);
});
```

<h4 id="V1M1Q"></h4>
#### Open the quick add-to-cart popup
+ **Event name**: `quick-add:open`
+ **Trigger timing**: Triggered when the action to open the add-to-cart popup is initiated. This is typically required during product addition scenarios.

<h5 id="mpnN9"></h5>
##### Standard data
```typescript
interface Detail {
  productHandle: string; // Product handle
}
```

<h5 id="u6f60"></h5>
##### Example
```javascript
// The "open quick add popup" event is triggered
window.themeEventCenter.dispatch(
  new ThemeEvent('quick-add:open', {
    detail: {
      productHandle: 'Shirt'
    }
  })
);
```

> **warning**
>
> **Note**: The logic for listening for the [Open the quick add-to-cart popup](#V1M1Q) event is already built in by the official theme. You do not need to implement it yourself.

