# Volume tiers events

> The DOM events and Shopify customer events the AndOr volume table and volume picker send, with payloads and listener examples, plus its data attributes and states.

Source: https://backtrackhq.com/docs/widgets/volume-tiers/events/

This page is for theme developers. The volume tiers host,
`<andor-tiers>`, sends the shared widget events and a tier change event.
With a live **Volume picker** upsell offer, its views, clicks and adds
are also published as upsell offer events for custom pixels.

All DOM events are `CustomEvent`s that bubble, so you can listen on
`document`. The `andor:offer_*` events are not DOM events. Subscribe to
them in a custom pixel.

> **Note:** A custom pixel is optional. AndOr counts offers without
> one. Add a pixel only if you want the `andor:offer_*` events in your
> own tools.

## Events

| Event | Sent on | When |
|---|---|---|
| `andor:widget:mount` | the host | the first pass that sees the widget |
| `andor:widget:unmount` | the host and `document` | the first pass after the widget left the page |
| `andor:display:change` | the host | the widget's state changed since the last pass |
| `andor:tier:change` | the host | the picked card or the highlighted table row moved to another step |
| `andor:offer_viewed` | customer events | the picker was first seen, once per offer and placement per visit |
| `andor:offer_clicked` | customer events | a shopper picked an option |
| `andor:offer_added` | customer events | the cart gained more of the picked variant after a pick |

Rules worth knowing:

- **No event on first paint**, and an unchanged state sends nothing.
- **One tier event per widget.** A page with a table and a picker sends
  two events for one quantity change. Check `detail.source` if you want
  only one.
- **The add is counted from the cart, not from the pick.** A shopper may
  pick 4 and never press **Add to cart**.

## Payloads

`andor:widget:mount`, `andor:widget:unmount` and
`andor:display:change` carry `event.detail.resource`:

| Field | Value for this widget |
|---|---|
| `widgetType` | `"tiers"` |
| `widgetId` | the block id, or `"pasted"` for a pasted tag |
| `productId` | the numeric product id, or `null` |

`andor:display:change` adds `previous` and `current` state objects:

| State field | Value for this widget |
|---|---|
| `discountId` | the volume discount shown (`data-andor-discount-id`) |
| `kind` | `"percentage"` |
| `mode` | `"badge_only"` |
| `visible` | `true` while the widget shows |
| `endsAt` | the end time (ISO 8601), or `null` |
| `priceCents` | `null` |
| `originalCents` | `data-price`, the variant price in cents |

`andor:tier:change` carries `event.detail`:

| Field | Type | Meaning |
|---|---|---|
| `productId` | number or `null` | the product |
| `variantId` | number or `null` | the variant on screen |
| `previousTier` | tier or `null` | the step before |
| `currentTier` | tier or `null` | the step now |
| `source` | `"picker"` or `"table"` | which widget sent it |
| `widgetId` | string or `null` | the host's `data-andor-widget-id` |

A tier is `{ index, quantity }`. `index` is 0 based among the steps.
`null` means below the first step (the "1 item" card). Example: a
shopper picks "4 items" after "2 items". `previousTier` is
`{ index: 0, quantity: 2 }` and `currentTier` is
`{ index: 1, quantity: 4 }`.

The `andor:offer_*` events carry `event.customData`:

| Field | Type | Meaning |
|---|---|---|
| `offerId` | string (digits) | the upsell offer |
| `placement` | `"product_page"` | where the offer showed |
| `valueCents` | number | adds only: the value added, in cents |

No customer data, cart token or product ids are sent.

## Examples

Log the picker's step:

```js
document.addEventListener("andor:tier:change", (event) => {
  const { currentTier, source } = event.detail;
  if (source !== "picker") return;
  console.log(currentTier ? `tier ${currentTier.quantity}+` : "no tier");
});
```

Optional: count picker adds in a custom pixel:

```js
// Shopify admin: Settings > Customer events > Add custom pixel
analytics.subscribe("andor:offer_added", (event) => {
  const { offerId, placement, valueCents } = event.customData;
  console.log("upsell add", offerId, placement, valueCents);
});
```

## Data attributes and states

### Volume table

| Attribute or class | On | Meaning |
|---|---|---|
| `.andor-tiers__row--current` | row | the tier the quantity reaches |
| `aria-current="true"` | row | the same, for screen readers |
| `data-andor-tier` | row | the threshold, "2" or "100.00" |
| `data-andor-off` | row | the percentage, "10" |
| `data-andor-basis` | host | `quantity` or `subtotal` |
| `hidden` | row | a tier that does not beat a sale here |

Tier rows and cards also carry `data-tier-index` (0 based) and
`data-tier-quantity`:

```css
.andor-tiers__row[data-tier-index="0"] { font-weight: 600; }
```

### Volume picker cards

| Attribute or class | On | Meaning |
|---|---|---|
| `aria-checked="true"` | card | the picked card |
| `data-andor-pick` | card | the quantity the card sets |
| `data-andor-tier` | card | a tier's threshold (none on "1 item") |
| `data-layout` | host | `list`, `mini`, `boxes` or `table` |
| `data-andor-scroll` | host | Boxes scroll sideways on a narrow host |

For the attributes every widget shares, like `data-andor-state` and
`data-andor-progress`, see
[Data attributes and states](https://backtrackhq.com/docs/developers/data-attributes/).
