# QuantityBreaks

> Volume discount selector — classic list, image pack cards, or supply-duration columns. Emits tiers:changed to re-price PlanSelector and BuyBox.

Canonical URL: https://fa7e86e3d553:3005/islands/commerce/quantity-breaks

> Volume discount selector. Place near BuyBox to encourage larger orders. Three layouts: classic `list` rows, `cards` with per-tier product imagery and badges, or `columns` with percent-off footer strips. With `emitEvents:true` it broadcasts `tiers:changed` so a [PlanSelector](/islands/commerce/plan-selector) or [BuyBox](/islands/commerce/buy-box) re-prices live.

## Preview

**Category**: Commerce

## Props

| Prop | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| tiers | array | Yes | - | Tier objects (see Tier fields below) |
| variantId | string | Yes | - | Shopify variant ID for the product (per-tier `variantId` overrides) |
| variant | enum | No | "list" | `"list"` (classic rows), `"cards"` (image pack cards), `"columns"` (supply-duration tiles with %-off footer) |
| emitEvents | boolean | No | false | Emit `tiers:changed` on mount and every selection |
| showCta | boolean | No | true | Render the built-in Add to Cart button; set `false` to use as a pure selector feeding PlanSelector/BuyBox |
| defaultSelected | number | No | 0 | Index of the pre-selected tier |
| currency | string | No | - | Currency symbol (defaults to store currency) |

### Tier fields

| Field | Type | Description |
|-------|------|-------------|
| quantity | number | Units added to cart |
| price | string | One-time total, pre-formatted ("$59.95") |
| perUnit | string | Per-unit cost line ("$0.66 / gummy" or "$23.99/pack") |
| label | string | Tier name ("3 Pack") |
| eyebrow | string | Small line above the label ("60 Days") |
| badge | string | Floating chip ("Most Popular", "Best Value") |
| compareAtPrice | string | Strikethrough price |
| savings | string | Savings text; renders as the footer strip in `columns` ("34% off") |
| image | string | Product image URL (cards variant) |
| imageCount | number | Repeat the image overlapped N times (multi-bottle look) |
| subscribePrice / subscribeCompareAt / subscribePerUnit | string | Pre-computed subscription prices carried in `tiers:changed` for PlanSelector |
| cadence | string | Auto-ship cadence line ("3 Packs Auto-Shipped Every 3 Months") |
| variantId | string | Per-tier variant override |

## Embed Example

```html
<lx-island name="QuantityBreaks">
  <script type="application/json">
{
  "tiers": [
    {
      "quantity": 0,
      "price": "example-price",
      "perUnit": "example-perUnit"
    }
  ],
  "variantId": "example-variantId"
}
  </script>
</lx-island>
```

## Usage Patterns

**Image pack cards feeding a PlanSelector (Purna-style):**

```html
<lx-island name="QuantityBreaks">
  <script type="application/json">
{
  "tiers": [
    {
      "quantity": 0,
      "price": "example-price",
      "perUnit": "example-perUnit"
    }
  ],
  "variantId": "example-variantId"
}
  </script>
</lx-island>
```

**Supply-duration columns with %-off footers (NuStrips-style):**

```html
<lx-island name="QuantityBreaks">
  <script type="application/json">
{
  "tiers": [
    {
      "quantity": 0,
      "price": "example-price",
      "perUnit": "example-perUnit"
    }
  ],
  "variantId": "example-variantId"
}
  </script>
</lx-island>
```

**Classic list with its own Add to Cart (standalone):**

```html
<lx-island name="QuantityBreaks">
  <script type="application/json">
{
  "tiers": [
    {
      "quantity": 0,
      "price": "example-price",
      "perUnit": "example-perUnit"
    }
  ],
  "variantId": "example-variantId"
}
  </script>
</lx-island>
```

## Events

| Event | Direction | Payload |
|-------|-----------|---------|
| tiers:changed | Emits (when `emitEvents:true`) | `{quantity, label?, price, compareAtPrice?, perUnit?, subscribePrice?, subscribeCompareAt?, subscribePerUnit?, cadence?, variantId?}` on mount and every tier selection |

## Tips

- Place directly below or beside [BuyBox](/islands/commerce/buy-box) for AOV uplift
- With a [PlanSelector](/islands/commerce/plan-selector): set `showCta:false` + `emitEvents:true` and let BuyBox own the CTA
- BuyBox with `listenForEvents:true` picks up quantity + tier price automatically from `tiers:changed`
- Pre-compute all prices as display strings (`subscribePrice` etc.) — the island does no money math
- Badge the middle tier "Most Popular" (social proof), the highest "Best Value" (value anchor)
- Use 3 tiers (1, 2, 3 or 1, 3, 6) — more than 4 causes decision paralysis
- Selection state is exposed as `data-selected="true"` — restyle it entirely from section CSS
- Works best for consumables (supplements, skincare, coffee, snacks)
- Alternative: use [BundleBuilder](/islands/commerce/bundle-builder) for "Frequently Bought Together" (different products)

## Stylable Parts

Target internal elements via `data-part` selectors in section CSS:

| Part | Description |
|------|-------------|
| `root` | Outermost container (carries `data-variant`) |
| `tier` | One tier option (carries `data-selected="true"` when active) |
| `tier-eyebrow` | Small line above the label |
| `tier-qty` | Tier label / quantity |
| `tier-badge` | Badge chip |
| `tier-image` | Image row (cards variant) |
| `tier-price` | Total price |
| `tier-compare` | Compare-at strikethrough |
| `tier-per-unit` | Per-unit cost line |
| `tier-discount` | Savings line (list/cards) |
| `tier-footer` | Percent-off footer strip (columns variant) |
| `tier-body` | Upper body of a column tile |
| `tier-radio` | Radio circle (list variant) |
| `cta` | Built-in Add to Cart button |

```css
/* Example: re-theme the selected tier */
[data-part="tier"][data-selected="true"] {
  border-color: var(--lx-accent-color);
  background: var(--lx-surface-alt);
}
```

## Related Islands

- [PlanSelector](/islands/commerce/plan-selector) — Subscribe & Save cards that re-price from `tiers:changed`
- [BuyBox](/islands/commerce/buy-box) — Listens to `tiers:changed` to update quantity and price
- [BundleBuilder](/islands/commerce/bundle-builder) — Alternative for cross-product bundles instead of quantity discounts
- [SubscriptionToggle](/islands/commerce/subscription-toggle) — Lightweight toggle when full plan cards are overkill
