swish.state signals declaratively. Drop them into Liquid (or any HTML) without writing JavaScript.
<swish-save>
Wraps a merchant-provided save button. Click toggles the saved state for the product. The SDK reflects status on the element so CSS and conditional children can react.
Inputs
Prefer
context over explicit IDs - it reacts to URL changes (PDP SPAs) and href changes (variant pickers that update product card links) automatically. Set product/variant only when the DOM doesn’t carry the product reference you need.
If none of the above are set, the SDK falls back to reading data-product-id, data-product-handle, data-variant-id, or data-item-id from the element itself.
Outputs
Examples
- PDP
- Collection card
The SDK reads the product from
window.location and watches for SPA navigation.context attribute does double duty: it drives the resolver and gives CSS a hook for styling variants of the same element.
<swish-drawer>
Wraps a merchant-provided drawer trigger button. Click opens the drawer to the given view via the intents system. The SDK reflects whether there are saved items and exposes the count for badge binding.
Inputs
Unknown
view values log a warning and fall back to "home".
view="profile" is the account entry point: a signed-in customer gets the profile view, a signed-out one goes straight to sign-in and returns to the page they left. Every other view opens the drawer whether or not the customer is signed in.
When the element wraps a link, holding Cmd, Ctrl, Shift or Alt while clicking opens that link instead - so a wrapped account link still opens in a new tab or window the way customers expect. Around a button there’s no link to open, so every click opens the view.
Outputs
Example: header trigger with count badge
textContent via data-swish-bind="count", and toggles the badge’s hidden based on the data-swish-when="has-saves" state. No JS required. The examples page shows the same badge built with swish.state.itemCount() and with the React hook.
Styling the badge count
The Account link placement (see the account guide) wraps your theme’s own account link, where there’s nowhere for you to add a badge element. badge="true" renders one: a span.swish-drawer-badge in the element’s top-right corner, hidden while the customer has nothing saved, and aria-hidden so the wrapped link keeps naming the control.
Restyle it with custom properties rather than overriding the rules - they win without a specificity fight:
background, color, size, font-size, font-weight, padding, border-radius, inset, offset-x and offset-y, each prefixed --swish-drawer-badge-.
These rules ship with the placement, scoped to it. In a <swish-drawer> you write into the theme yourself, add the badge span shown above instead and style it as your own markup.
Child conventions
data-swish-when
Place on a descendant of <swish-save> or <swish-drawer>. The SDK toggles native hidden so the descendant is shown only when the parent’s state attribute matches. Pass a comma-separated list to show the same content for multiple states - useful for optimistic UI where the post-click “saving” state should look identical to the resolved “saved” state.
hidden on non-default states in your template so the markup renders correctly before the SDK hydrates.
data-swish-bind
Place on a descendant of <swish-drawer>. The SDK writes the bound value to textContent. Combine with data-swish-when on the same element when you need to hide the binding for empty states - the example badge uses data-swish-bind="count" data-swish-when="has-saves" hidden so it stays hidden when the customer has no saved items.
While the sign-in requirement is
"save" or "all", count reads 0 and state reads empty for a signed-out customer, since they can’t save until they sign in.
Styling
Class hooks
The custom elements impose no CSS. Add your own classes to the inner button and children - styles cascade in normally (no Shadow DOM). The canonical sample usesswish-save-button, swish-save-icon, swish-save-label and swish-drawer-button, swish-drawer-icon, swish-drawer-badge so support devs have predictable selectors when overriding per-merchant styles.
Pre-paint hiding with ready
Before the SDK boots, custom elements render their markup as-is. For places where a layout shift would be jarring (product card grids), opt into pre-paint hiding by targeting :not([ready]):
Liquid snippet
Drop the snippet below intosnippets/swish.liquid and the stylesheet into assets/swish-theme.css. The snippet dispatches between the elements by name; when called with no arguments it sets window.SwishOptions and loads swish-theme.css.
Usage in theme.liquid:
snippets/swish.liquid
snippets/swish.liquid
assets/swish-theme.css
Starter stylesheet with every selector the snippet renders. Paste merchant button styles into the empty rule bodies.
assets/swish-theme.css