> ## Documentation Index
> Fetch the complete documentation index at: https://discountkit.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Events

> The events <dkl-price> listens for and emits

`<dkl-price>` is event-driven. It has **no direct reference** to the
[volume picker](/components/volume-picker/overview) — instead it listens for the picker's tier-change
event and the theme's variant-change events, and updates the price accordingly.

## Listens for

<ParamField body="discount-kit-live:volume-discount:tier-change" type="CustomEvent">
  Emitted by the [volume picker](/components/volume-picker/overview). Matched by product id — a
  selected tier shows the discounted price, a `null` tier reverts to base. Coupling is by
  event name and product id only, with no import between the two components.

  Honours the event's `updatesPrice` flag: if the picker's **"Update price when a tier is
  selected"** setting is off, `<dkl-price>` **ignores the tier for pricing** (the event still
  fires for other listeners).
</ParamField>

It also reacts to the host theme's **variant-change** events: on a variant change it updates
the base price and re-applies the active tier, recomputing the discount off the new variant's
price (sale-priced variants included).

## Emits

`<dkl-price>` emits a **price-change** event whenever its displayed price updates, plus
**mount / unmount** lifecycle events. All bubble, so you can listen on `document`.

<Note>
  **`widgetId` and `variantId`.** `widgetId` is the **app block's id** — it's `null` on a web component,
  `variantId` is the **current** variant and
  updates as the shopper switches variants (not just the variant at page load).
</Note>

### Price change

<ParamField body="discount-kit-live:price:change" type="CustomEvent">
  Fired whenever the displayed price changes — when a volume tier is selected or deselected, or
  the variant changes. **Not** fired on initial mount (the server-rendered price is already in
  the DOM), and **deduped** — a recompute that lands on the same price (e.g. switching to an
  equally-priced variant) doesn't fire. The detail carries `resource` with the previous and new
  price, mirroring the tier event's `previousTier` / `currentTier`:

  ```ts theme={null}
  resource: {
    widgetType: 'price'
    widgetId: string | null
    productId: number | null
    variantId: number | null
    previousPrice: PriceState | null   // null on the first change after mount
    currentPrice:  PriceState
  }

  type PriceState = {
    priceCents: number              // displayed price (discounted when a tier is active)
    compareAtCents: number | null   // the struck-through "before" price, or null
    discounted: boolean             // whether a volume tier is applied
    tier: VolumeDiscountTier | null // the active tier, or null
  }
  // VolumeDiscountTier: { index, quantity, discountAmount, discountType, unitPriceCents }
  ```
</ParamField>

A full example payload — selecting a tier that moves the price from £20.00 to £18.00:

```js theme={null}
// event.detail.resource on price:change
{
  widgetType: 'price',
  widgetId: 'a1b2c3d4',        // the app block's id (null on a web component)
  productId: 7820000000001,
  variantId: 41200000000001,   // the current variant — updates on a variant change
  previousPrice: {
    priceCents: 2000,
    compareAtCents: null,
    discounted: false,
    tier: null
  },
  currentPrice: {
    priceCents: 1800,
    compareAtCents: 2000,      // the original price, now struck through
    discounted: true,
    tier: {
      index: 1,
      quantity: 3,
      discountAmount: 10,
      discountType: 'percentage',
      unitPriceCents: 1800
    }
  }
}
```

### Lifecycle

The mount / unmount events fire as the instance's behaviour attaches and tears down — handy
for wiring up (and cleaning up) custom integrations per instance. Both carry a
`DklWidgetEventDetail` resource.

<ParamField body="discount-kit-live:widget:mount" type="CustomEvent">
  Fired once the controller has attached its behaviour to the (already server-rendered)
  element. `resource`: `{ widgetType, widgetId, productId?, variantId? }` — `productId` and
  `variantId` are included when known.
</ParamField>

<ParamField body="discount-kit-live:widget:unmount" type="CustomEvent">
  Fired when the instance tears down — e.g. the element is removed, or the theme editor
  re-renders the section. Same `resource` shape. Use it to detach any listeners or observers
  you set up on mount.
</ParamField>

```js theme={null}
// event.detail.resource on widget:mount / widget:unmount
{
  widgetType: 'price',
  widgetId: 'a1b2c3d4',        // the app block's id (null on a web component)
  productId: 7820000000001,
  variantId: 41200000000001
}
```

## Next steps

<CardGroup cols={2}>
  <Card title="Web Components" icon="code" href="/components/price/web-component">
    Listener and `MutationObserver` examples for reacting to changes.
  </Card>

  <Card title="Volume Picker" icon="layer-group" href="/components/volume-picker/overview">
    The component that emits the tier-change event.
  </Card>
</CardGroup>
