# Wire the widget into your page

The widget reads four kinds of markup on your page: buy links, a cart button
and a counter, its own container, and content slots in the checkout.

## Sell from your own links

Turn on `interceptProductLinks` and the widget watches every click on the
page. When the link points at a Subbly product, bundle or survey, the widget
cancels the navigation and calls
[`configureItem`](/reference/cart-widget/methods#configure-item) with a
quantity of `1`. So a buy button is an ordinary link:

```html title="Buy buttons"
<script>
  window.subblyConfig = {
    apiKey: 'YOUR_STOREFRONT_API_KEY',
    settings: { interceptProductLinks: true }
  }
</script>

<a href="/checkout/buy/555">Subscribe</a>
<a href="/checkout/buy/bundle/42?coupon=WELCOME10">Build your box</a>
<a href="/checkout/buy/survey/7">Take the quiz</a>
<a href="/checkout/buy/555?gift=1">Send as a gift</a>
```

The widget reads the nearest `<a>` above the clicked element, ignores the host
name, and matches case-insensitively, so a link to the Subbly-hosted checkout
works as well as a path on your own site. `add` and `buy` are both accepted.

| Link | What it does |
| :-- | :-- |
| `/checkout/buy/{productId}` | Adds a product. The widget asks for the plan or the variant when the customer still has a choice to make. |
| `/checkout/buy/bundle/{bundleId}` | Opens the bundle builder. |
| `/checkout/buy/survey/{surveyId}` | Starts the survey flow. |
| `?gift=1` | Any value opens the gift view after the item is added. |
| `?coupon=CODE` | Holds the coupon and applies it once the cart fits it. |

When a link cannot carry a Subbly URL, put the product ID (digits only) in a
`data-subbly-product` attribute instead. The widget reads it from the nearest
`<a>` above the clicked element; a Subbly URL in the `href` wins when the link
carries both.

```html title="A button with no Subbly URL"
<a href="#" data-subbly-product="555">Subscribe</a>
```

Before the widget has loaded, a stub handler cancels clicks on these links but
does not remember them. A click that early is dropped.

## Show your own cart button and item count

The widget can draw a floating cart button (`cartButton: true`), but most
sites have a cart icon of their own. Point the widget at it with
`cartToggleEl`, and at the badge that shows the number of items with
`cartCounterEl`. Both take a CSS selector or an element:

```html title="Your own cart button"
<a href="#" class="js-cart-toggle">
  Cart (<span class="js-cart-count">0</span>)
</a>

<script>
  window.subblyConfig = {
    apiKey: 'YOUR_STOREFRONT_API_KEY',
    settings: {
      cartToggleEl: '.js-cart-toggle',
      cartCounterEl: '.js-cart-count'
    }
  }
</script>
```

A click on a toggle match opens or closes the widget, and the default click
action is cancelled. The widget replaces the content of every counter match
with the number of active items on every cart change. Clicks are caught on
`document`, so a header your framework renders later still works. On a
framework that routes with `pushState`, update the counter yourself from
[`CART_UPDATED`](/reference/cart-widget/events#cart-updated).

One more selector needs no setting: when the page holds an `a.subbly-cart`,
the widget hides its own floating cart button.

Both keys are on [Settings keys](/reference/cart-widget/settings#settings).

## Place the widget

The widget mounts in a `div#subbly-cart-widget`. By default it creates the
element, appends it to `<body>`, and gives it `position: fixed`,
`z-index: 2147483000` and the class `SubblyAppContainer`. The app renders
inside, under `.SubblyApp`.

To choose where the element sits, put an empty one in your markup and the
widget reuses it in place. Any other element with that ID is left alone, and
the widget creates its own with a random suffix, such as
`subbly-cart-widget-a1b2c`.

```html title="Place the container yourself"
<div id="subbly-cart-widget"></div>
```

The class names inside are hashed at build time and change between releases.
Style the widget through its
[CSS variables](/reference/cart-widget/theming#css-variables), not its
classes.

## Add content to the checkout

The checkout and the receipt render empty elements with stable IDs at fixed
points. Each collapses while it is empty, so filling one leaves no gap when
you do not.

Fill them from Checkout JS, which you write in the Subbly admin under Shop
settings, Checkout JS. It reaches the page as `subblyCart.shop.checkoutJs`.
The widget injects it only in standalone checkout mode (`checkoutOnly: true`):
it re-creates inline `<script>` tags and appends them to `<body>`, appends
external scripts to `<body>`, and appends `<link>` tags to `<head>`. On a
normal page it never runs, so read `subblyCart.shop.checkoutJs` and inject it
yourself if you need it there.

```js title="Reassure the customer under the pay button"
const slot = document.getElementById('widgetSlot__payButtonAfter')

if (slot) {
  slot.innerHTML = '<p>Cancel any time. No questions asked.</p>'
}
```

| Slot ID | Where it renders |
| :-- | :-- |
| `widgetSlot__checkoutAccountBefore` | Above the account section of the checkout. |
| `widgetSlot__shippingBefore` | Above the shipping address section. |
| `widgetSlot__shippingMethodBefore` | Above the shipping method section. |
| `widgetSlot__paymentBefore` | Above the payment section. |
| `widgetSlot__paymentCreateFormBefore` | Above the new payment method form. |
| `widgetSlot__paymentCreateStripeAfter` | Below the Stripe card form. |
| `widgetSlot__payButtonAfter` | Below the pay button. |
| `widgetSlot__summarySectionAfter` | Below the order summary. |
| `widgetSlot__purchaseBeforeTitle` | Above the title of the receipt. |
| `widgetSlot__purchaseAfterTitle` | Below the title of the receipt. |
| `widgetSlot__purchaseBeforeReceipt` | Above the receipt. |
| `widgetSlot__purchaseAfterReceipt` | Below the receipt. |
| `widgetSlot__purchaseBeforeItems` | Above the bought items. |
| `widgetSlot__purchaseBeforeActions` | Above the buttons on the receipt. |
| `widgetSlot__purchaseAfterActions` | Below the buttons on the receipt. |
