- Custom element - wrap your own markup, no JavaScript. The SDK binds state to
data-swish-*attributes. Start here on a Liquid theme. - State helper - the same signals the elements bind, called from your own script. Use it when the markup is generated at runtime or no element covers the case yet.
- React - the
@swishapp/reacthooks, for Hydrogen and other headless storefronts.
window.swish exists. If your script can run before the SDK boots, wait for it once and put the samples inside:
Save button
A save/unsave toggle on a product page, or inside a product card on a collection page.- Custom element
- State helper
- React
context="pdp" reads the product from the page URL and follows SPA navigation. context="product-card" walks to the nearest product link in the surrounding card and follows its href. Children marked data-swish-when are shown only in the listed states.Header badge and drawer trigger
A header icon that shows how many items the customer has saved and opens the drawer on click.- Custom element
- State helper
- React
data-swish-bind="count" receives the live count. data-swish-when="has-saves" hides the badge while nothing is saved.Custom wishlist page
A standalone page that renders every saved item, or the list a share link orview:list intent points at. Mount it at routes.listDetailPagePath (default /apps/wishlist) so share links and deep links land on it.
There is no declarative element for a list of items yet, so this example has
no custom element tab.
- State helper
- React
Start by loading the collection and logging it. This runs in any environment, including the browser console on your store.Three things to know before rendering:Add to cart with
- The effect runs again on every change to the collection - a save from the built-in drawer, an unsave from your page, a sign-in, or a call to
items.loadMore()for the next page. Render fromitems.valueand never keep your own copy. - Items carry Shopify IDs only. Resolve product data per card with
product(), which shares one cache across the page. - Actions go through intents, so the built-in UI and your page stay in sync. The
unsave:itemintent removes an item, and the collection drops it when theitem-deleteevent fires.
product() is cached, so no request repeats. Each card adds its image only once product() resolves with an image URL, because an <img> without a src shows as a broken image until then.swish.intents.invoke("create:cart-line", { variantId: item.variantId }) and share the list with swish.intents.invoke("initiate:share", { listId: context.value.listId }). In a component framework that unmounts cards, call product.dispose() when the card goes away.Drawer with list tabs
A drawer that shows the customer’s named lists, “Saved from cart”, and “Recently viewed” as tabs above one grid.- State helper
One signal holds the current list context. One Smart lists come back from
items() collection follows it, so switching tabs never rebuilds the collection. lists() supplies the tab labels and itemCount() the “All” badge.lists() with type: "smart", so the same tab factory covers them.React to a save from anywhere
Run code when the customer saves an item, whether from your button, the built-in drawer, or a product card.- Events
- State helper
The event bus fires for every save on the page.
Next
State
Every signal these examples read, with its properties and methods.
Elements
Attributes and child conventions for swish-save and swish-drawer.
Intents
Every action a custom UI can trigger.
Events
Every change a custom UI can react to.