# Swym Wishlist for Retail Cloud Connect™ Product Cards

This guide adds a Swym Wishlist Plus heart to Retail Cloud Connect product cards with a **Custom** component. It is intended for theme developers and supports Swym's default single-list and guest-wishlist behavior.

The built-in **Wishlist** component remains a generic integration hook for wishlist apps that initialize from HTML attributes. Swym needs its own Web Component because product cards can be replaced after filtering or pagination and every visible heart must share the same saved state.

[!warning]
This example is not a drop-in implementation for stores that require sign-in or use multiple Swym lists. Review [Sign-In and Multiple Lists](#sign-in-and-multiple-lists) before publishing it.

<br/>

## Prerequisites

- Swym Wishlist Plus is installed and its App Embed is enabled in the target theme
- Swym works on an ordinary product page before the product-card integration is added
- The store's guest, required-sign-in, and single-list or multi-list policy is known
- A theme developer can add JavaScript and CSS assets to the target theme

Enable the target store's own Swym App Embed. Do not copy App Embed IDs, app UUIDs, or `config/settings_data.json` entries from another store.

<br/>

## Add the Web Component

Create `assets/rcc-product-wishlist.js` in the Shopify theme and add the following component:

:::code language="js" title="assets/rcc-product-wishlist.js" source="/static/code-snippets/rcc-product-wishlist.js" :::

The component uses only `product.productId`, `product.variantId`, and `product.url`. Retail Cloud Connect assigns those values through the element's `product` property, so this integration does not need a metafield, Storefront GraphQL requirement, or request from each product card.

The component also:

- Normalizes numeric IDs, Shopify GIDs, and Retail Cloud Connect `@...` product suffixes before calling Swym
- Removes query parameters from the saved product URL
- Fetches the default wishlist once per page
- Uses one Swym event subscription to synchronize duplicate product cards
- Prevents a heart click from opening the product-card link
- Disables the button while an add or remove request is running

The example uses English accessible labels. Replace `Add to wishlist` and `Remove from wishlist` with the theme's locale strings on multilingual storefronts.

<br/>

## Load the Component Before App Blocks

Load the JavaScript synchronously in the document `<head>` before a Retail Cloud Connect App Block can render. The recommended location is `snippets/nimstrata.liquid`; see [nimstrata.liquid Setup](/shopify/theme-installation/nimstrata-liquid/).

:::code language="liquid" title="snippets/nimstrata.liquid" source="/static/code-snippets/rcc-product-wishlist.liquid" :::

Do not add `defer`, `async`, or `type="module"`. The Product Card renderer checks whether the Custom element is registered before rendering it.

The component accepts Swym through its callback queue and also handles a Swym instance that has already loaded. Its registration guard prevents duplicate theme includes or Theme Editor reloads from binding the integration twice.

<br/>

## Add It in the Product Card Builder

In the Retail Cloud Connect Shopify App:

1. Open **Product Card Builder**.
2. Add a **Custom** component to the product-card block that contains the image.
3. Set **Component** to `rcc-product-wishlist`.
4. Leave Product metafields empty.
5. Save and publish the layout.

The component name must match exactly. A JavaScript file alone does not add the component to the product-card layout.

<br/>

## Add the Styles

Add the following rules to the theme stylesheet. The first selector assumes the Custom component is inside the standard vertical image block; use the actual nearest product-card wrapper if the store's layout differs.

```css assets/base.css
.rcc-search__product__block--vertical {
  position: relative;
}

rcc-product-wishlist {
  position: absolute;
  top: 0.5rem;
  right: 0.5rem;
  z-index: 5;
  display: block;
}

rcc-product-wishlist:empty {
  display: none;
}

.rcc-product-wishlist__button {
  display: grid;
  width: 2.75rem;
  height: 2.75rem;
  padding: 0;
  place-items: center;
  color: var(--color-foreground, #1f1f1f);
  background: var(--color-background, #fff);
  border: 1px solid currentColor;
  border-radius: 50%;
  cursor: pointer;
}

.rcc-product-wishlist__button svg {
  width: 1.4rem;
  fill: transparent;
  stroke: currentColor;
  stroke-width: 1.75;
}

.rcc-product-wishlist__button.swym-added svg {
  fill: currentColor;
}

.rcc-product-wishlist__button:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 2px;
}

.rcc-product-wishlist__button:disabled {
  cursor: wait;
  opacity: 0.6;
}
```

Keep the heart clear of badges and other overlays. Adjust `top`, `right`, and `z-index` for the active theme rather than applying global `.swym-button` overrides.

<br/>

## Sign-In and Multiple Lists

Some themes replace a Swym API to require authentication before a shopper can save an item. Calling the top-level `swat.addToWishList()` method directly can bypass a theme-specific sign-in override.

For a required-sign-in store, route the add action through the theme's documented public sign-in adapter. The adapter must accept the same `{ empi, epi, du }` item and replay the action after login. Do not mark the heart as saved before login and a successful replay. Keep the `data-rcc-wishlist-variant-id` hook from the example so replay code can locate the correct product card.

The example uses `swat.fetch()` and `swat.removeFromWishList()`, which cover the default wishlist. For multiple lists, confirm the API contract for the installed Swym version, hydrate all `listcontents` with `fetchLists()`, retain each list ID, and remove with `deleteFromList()` for the correct list.

Avoid adding Swym's native action classes or `data-swaction` to the custom button. A later Swym action-button scan can otherwise attach a second click handler and submit the same item twice.

[!ref target="\_blank" text="Swym Developer Documentation"](https://developers.getswym.com/)

<br/>

## Validation Checklist

- Run `node --check assets/rcc-product-wishlist.js` and Shopify Theme Check
- Confirm `customElements.get('rcc-product-wishlist')` is defined before product cards render
- Confirm each valid product card contains one wishlist button
- Test numeric, Shopify GID, and `@...` ID forms
- Verify each add request has the correct product ID, selected variant ID, and absolute product URL
- Add and remove while signed in, then reload and confirm the state persists
- Render the same variant more than once and confirm every heart stays synchronized
- Test filtering, sorting, pagination, and any Recommendations AI App Blocks that use the same product-card layout
- Confirm keyboard activation, visible focus, `aria-label`, and `aria-pressed`
- Confirm clicking the heart does not open the product and clicking elsewhere on the card still does
- Test signed-out behavior when the store requires sign-in
- Test products outside the default list when the store uses multiple lists
- Confirm Swym's native collection integration has not injected a second heart

<br/>

## Troubleshooting

| Symptom                                  | Likely cause {.compact}                                                                                               |
| ---------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
| The Custom component is absent           | The component name does not match, or its script loaded after the App Block rendered                                  |
| A heart click opens the product          | The button handler did not prevent the card-link click and stop propagation                                           |
| One click sends two requests             | Swym's native action-button initializer and the Custom component both bound the button                                |
| The saved heart remains empty            | Initial hydration did not run, IDs use different formats, or the installed Swym version exposes different event names |
| The wrong variant is saved               | The selected variant changed without rebuilding the Swym payload                                                      |
| Signed-out shoppers bypass login         | The component called the top-level add method instead of the store's sign-in adapter                                  |
| Products in another list look unsaved    | `fetch()` hydrated only the default list                                                                              |
| The heart overlaps a badge or is clipped | The wrong wrapper is positioned, an ancestor clips overflow, or overlay z-index values conflict                       |

<br/>

## Related Guides

- [Custom Components](/shopify/product-card-builder/custom-components/index.md) for the full Product Card Web Component contract
- [Product Card Builder](/shopify/product-card-builder/) for layout configuration
- [Customizing App Blocks](/shopify/theme-installation/customizing-app-blocks/) for product-card CSS hooks
