Skip to main content
Placements let you insert Swish elements (like Save and Home buttons) anywhere in your storefront. They use DOM observation to automatically mount when matching elements appear, and survive theme re-renders.

Declarative placements

Pass a placements array to createSwish() and the SDK mounts them automatically at initialization. This is the recommended approach when you know which placements you need upfront.
Each entry in the array uses the same placement spec documented below.

swish.placements.list

After initialization, all declarative placements are available at swish.placements.list. Each entry is an object with spec, mount, and unmount properties, so you can control individual placements programmatically:

swish.placements.create(spec)

Creates a placement and returns an object with mount() and unmount() methods.
  • mount() starts observing the DOM and inserts elements when targets are found.
  • unmount() removes all inserted elements and stops observing.

Placement spec

id

string
required
Unique identifier for this placement. Used internally for deduplication, stylesheet scoping, and DOM attributes.

target

Defines which elements in the page the placement should attach to. The SDK uses a MutationObserver to watch for matching elements, including elements added after initial page load.
string
required
CSS selector to match target elements.
boolean | ((element: Element) => boolean)
Optional filter. Return false to skip a matched element. A plain boolean is also accepted, so config-authored placements can serialize the switch without a function.
IntersectionObserverInit
If provided, the element is only mounted when it becomes visible in the viewport. Accepts standard IntersectionObserver options.

mount

Controls where the Swish element is inserted relative to the target.
string
required
Insertion mode. One of:
MountAt
Determines the reference element for insertion. Defaults to the target element itself. Options:

element

The Swish element to insert.
string
required
Element type. Currently supports "save-button" and "header-button".
Record<string, unknown>
Attributes to set on the element. Keys are converted to kebab-case (e.g. productId becomes product-id).For save-button, supported props include match: "variant" | "product" | "auto" to control how saved state is interpreted. Use match: "product" for cards that show a default variant but should reflect product-level saved state. See match options for details.icon: "heart" | "bookmark" | "star" picks this button’s glyph. Leave it out to use the store’s Save button icon style.
string[]
CSS classes to add to the element.
Alternatively, pass a function that returns an HTMLElement for full control:

style

"on-image" | "on-page"
Which look a save-button renders. On image is an icon-only chip for buttons over product media - by default a #121212 heart on a white chip. On page is a heart with its label for buttons in the page flow - by default white on a #121212 button, sized like your theme’s buttons. Each look has its own design tokens, and a look’s tokens never affect the other.A placement on a collection grid (element.props.context: "product-card") is always On image, whatever style says. Otherwise the default is "on-page". The SDK reflects the resolved look on the <swish-ui> host as swish-save-style="on-image" or swish-save-style="on-page", so custom CSS can target one look.
A placed save-button also plays the store’s save animation. The SDK reflects it on the host as swish-save-animation, for example swish-save-animation="pulse", and "none" when the store picked none.

layout

Optional layout strategy for positioning the inserted element.

Overlay

Positions the element absolutely over the target’s parent. Useful for floating a Save button on top of a product card image.
string
Corner to anchor to. One of "top-left", "top-right", "bottom-left", "bottom-right". Defaults to "bottom-right".
{ x?: number, y?: number }
Pixel offset from the anchor corner. Supports responsive values.
number | string
Custom z-index for the overlay: an integer (as a number or a string such as "20"), "auto", or a CSS-wide keyword such as "inherit". Any other value is ignored and the default 10 applies.

Inline

Wraps the reference element and the Swish element in a flex row, placing them side by side. Useful for adding a Save button next to an Add to Cart button.
string
If provided, the SDK uses an existing container as the flex row instead of creating a wrapper. The selector is resolved via closest() from the reference element.

Anchored

Positions the element relative to any element in the DOM, regardless of where the element is inserted. Unlike overlay, which requires the element to be a child of its positioning reference, anchored decouples DOM insertion from visual positioning. Use this when the element you want to overlay is a sibling or cousin of the mount target.
MountAt
The element to visually anchor to, resolved from the target element. Accepts the same values as mount.at. Defaults to the resolved mount target (renderTargetEl).
string
Where to position relative to the anchor element. Accepts any Floating UI placement string such as "top-start", "top-end", "bottom-start", "bottom-end", "top", "bottom", "left", or "right". Defaults to "bottom-end".
boolean
Position inside the anchor element’s bounds rather than adjacent to it. When true, the placement maps to corners within the anchor - for example, "top-end" places the element at the top-right corner inside the anchor. Defaults to false.
number
Pixel offset from the anchor. When inside is false, this pushes the element away from the anchor edge. When inside is true, this acts as an inward inset from the corner.
number | string
Custom z-index for the anchored element: an integer (as a number or a string such as "20"), "auto", or a CSS-wide keyword such as "inherit". Any other value is ignored. Defaults to 10.

design

Design tokens specific to the element type. Values are emitted as CSS custom properties scoped to the placement.

Save button design tokens

Home button design tokens

Left alone, the button is a 44px hit target around a 20px heart drawn in the header’s text colour — the look of a theme’s own header icons. The badge is centred on a corner of the heart icon itself, with no outline, so it stays on the heart when the button shows text: statusIndicatorInset picks the corner and the two offsets nudge from there.
background, color and radius were removed — no header stylesheet read them, so they persisted and published while rendering nothing. Use statusIndicatorBackground for the badge and iconColor for the icon.

container

Wraps the Swish element in an additional container element.
keyof HTMLElementTagNameMap
HTML tag for the container. Must be a valid HTML element tag name (e.g., "div", "span", "section"). Defaults to "div".
string[]
CSS classes to add to the container.

breakpoints

Customize the responsive breakpoints used by design and layout.offset values. Defaults to { sm: 500, lg: 700 }.

css

Raw CSS string appended after all generated styles. Use this as an escape hatch for styling that design tokens don’t cover.

onMount / onUnmount

Lifecycle callbacks invoked when the element is inserted into or removed from the DOM.
The MountContext passed to onMount includes:

Responsive values

Any design token or overlay offset accepts responsive values. Pass an object with base and breakpoint keys:
The base value applies at all screen sizes. Breakpoint values apply at their min-width and above.

Ignoring elements

Add the swish-ignore attribute to any element to prevent placements from mounting on it:

Examples

Overlay Save button on product cards

Anchored Save button on product images

Mounts the button into the product card, but visually positions it inside the top-right corner of the product image. This works even when the image and the mount point are siblings in the DOM.

Inline Save button next to Add to Cart

Lazy-mount on scroll