> For the complete documentation index, see [llms.txt](https://docs.elitebundleapp.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.elitebundleapp.com/reference/events.md).

# Events

All events are dispatched on `document` as `CustomEvent` instances with `bubbles: true`. Listen with `document.addEventListener` or the convenience wrappers `window.eliteBundle.on` / `window.eliteBundle.off`.

```js
window.eliteBundle.on('elite:byob:ready', (event) => {
  console.log(event.detail); // { bundleId, stepCount }
});
```

***

## BYOB Events

### `elite:byob:ready`

Fired once after BYOB finishes loading products from the Storefront API and React has mounted. This is the safe point to start reading `window.eliteBundle.sdk.byob`.

**Detail:**

```ts
{
  bundleId: string;   // Shopify product ID
  stepCount: number;  // number of configured steps
}
```

**Example:**

```js
document.addEventListener('elite:byob:ready', (event) => {
  const { bundleId, stepCount } = event.detail;
  console.log(`Bundle ${bundleId} loaded with ${stepCount} steps`);

  const { steps } = window.eliteBundle.sdk.byob;
  renderMySteps(steps);
});
```

***

### `elite:byob:error`

Fired when BYOB fails to load (e.g. Storefront API error, network failure).

**Detail:**

```ts
{
  error: string; // human-readable error message
}
```

**Example:**

```js
document.addEventListener('elite:byob:error', (event) => {
  showErrorBanner(event.detail.error);
});
```

***

### `elite:byob:cart-change`

Fired after every cart mutation: add, remove, or quantity update. Use this to keep your custom cart UI in sync.

**Detail:**

```ts
{
  cart: CartItem[];
  cartTotal: number;
  cartTotalFormatted: string;  // e.g. "$49.99"
  cartCount: number;
  canCheckout: boolean;
}
```

**Example:**

```js
document.addEventListener('elite:byob:cart-change', (event) => {
  const { cart, cartTotalFormatted, cartCount, canCheckout } = event.detail;

  document.querySelector('#cart-count').textContent = cartCount;
  document.querySelector('#cart-total').textContent = cartTotalFormatted;
  document.querySelector('#checkout-btn').disabled = !canCheckout;

  renderCartItems(cart);
});
```

***

### `elite:byob:checkout-start`

Fired when `checkout()` is called, before the cart POST request is sent.

**Detail:**

```ts
{
  cart: CartItem[];
  cartTotal: number;
  cartCount: number;
}
```

**Example:**

```js
document.addEventListener('elite:byob:checkout-start', () => {
  document.querySelector('#checkout-btn').textContent = 'Processing…';
});
```

***

### `elite:byob:checkout-success`

Fired after the cart POST request succeeds. If `redirectTarget` is `"checkout"` or `"cart"`, the page navigates immediately after this event.

**Detail:**

```ts
{
  redirectTarget: "checkout" | "cart" | "stay_on_page";
}
```

***

### `elite:byob:checkout-error`

Fired when the cart POST request fails.

**Detail:**

```ts
{
  error: string; // human-readable error message
}
```

**Example:**

```js
document.addEventListener('elite:byob:checkout-error', (event) => {
  document.querySelector('#checkout-btn').textContent = 'Try again';
  showToast(event.detail.error);
});
```

***

## MOB Events

### `elite:mob:ready`

Fired once after MOB finishes loading products and React has mounted. Safe point to start reading `window.eliteBundle.sdk.mob`.

**Detail:**

```ts
{
  bundleId: string;    // Shopify product ID
  optionCount: number; // number of configured options
}
```

**Example:**

```js
document.addEventListener('elite:mob:ready', (event) => {
  const { optionCount } = event.detail;
  console.log(`MOB loaded with ${optionCount} options`);

  const { options, selectableItems } = window.eliteBundle.sdk.mob;
  renderMyPicker(options, selectableItems);
});
```

***

### `elite:mob:error`

Fired when MOB fails to load.

**Detail:**

```ts
{
  error: string;
}
```

***

### `elite:mob:selection-change`

Fired after any selection change: `selectItem` or `setOptionSelection`. Use this to update price displays and enable/disable the add-to-cart button.

**Detail:**

```ts
{
  selectedVariants: (ProductVariant | null)[];
  selectedItemKeys: Record<number, string | null>;
  allSelected: boolean;
  totalPrice: number;
  totalPriceFormatted: string;
  discountedPrice: number | null;
  discountedPriceFormatted: string | null;
}
```

**Example:**

```js
document.addEventListener('elite:mob:selection-change', (event) => {
  const {
    allSelected,
    totalPriceFormatted,
    discountedPriceFormatted,
    selectedItemKeys,
  } = event.detail;

  document.querySelector('#add-btn').disabled = !allSelected;

  const priceEl = document.querySelector('#price');
  if (discountedPriceFormatted) {
    priceEl.innerHTML = `<s>${totalPriceFormatted}</s> ${discountedPriceFormatted}`;
  } else {
    priceEl.textContent = totalPriceFormatted;
  }
});
```

***

### `elite:mob:cart-add-start`

Fired when `addToCart()` is called, before the cart POST request.

**Detail:**

```ts
{
  selectedVariants: (ProductVariant | null)[];
}
```

***

### `elite:mob:cart-add-success`

Fired after the cart POST request succeeds.

**Detail:**

```ts
{
  redirectTarget: "checkout" | "cart" | "stay_on_page";
}
```

***

### `elite:mob:cart-add-error`

Fired when the cart POST request fails.

**Detail:**

```ts
{
  error: string;
}
```

***

## Event timing

Both `elite:byob:ready` and `elite:mob:ready` can fire before your theme JavaScript runs, depending on load order. Always guard against this:

```js
function onBundleReady(type, callback) {
  if (!window.eliteBundle?.sdk) return; // SDK not enabled

  const eventName = type === 'mob' ? 'elite:mob:ready' : 'elite:byob:ready';
  document.addEventListener(eventName, callback);

  // Handle the case where ready already fired before this script ran
  const sdk = window.eliteBundle.sdk[type];
  if (sdk && !sdk.isLoading && !sdk.error) callback();
}

onBundleReady('byob', () => {
  // safe to use window.eliteBundle.sdk.byob here
});
```

See [Getting Started](/developer-docs/getting-started.md) for the full guard pattern.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.elitebundleapp.com/reference/events.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
