Ask in a dialog before saving from the cart
Removing an item from the cart can now open a dialog that asks the customer whether to save it, which is harder to miss on a wide screen than the toast. Set Global → Preferences → Cart → Ask before saving a cart line to Ask in a dialog, orintents.saveCartLine.confirm to "dialog". Ask in a toast ("toast", or true as before) keeps the prompt in the toast. Change the dialog’s text with the saveForLaterAlert keys in translations.Saves reach the Meta Pixel
Every save from a customer who allows marketing now fires Meta’s standardAddToWishlist event on your Meta Pixel, with the saved variant as the content ID and its price in currency units, so saves can build audiences and retargeting alongside views and add-to-carts. With the pixel loaded in your theme there is nothing to do. With the pixel installed by the Facebook & Instagram app, a short custom pixel forwards the event; the Meta Pixel page has it. It is on for every store, and integrations.metaPixel.enabled: false in window.SwishOptions turns it off.A subtitle on product cards
TheproductSubtitle transform adds a line under the product title on product cards, in the drawer and on the Wishlist page. Return the text to show, for example the colour of a product from a combined listing once Color is out of the option select, or a value from a product metafield. It shows in the subdued text colour between the title and the price. Return nothing to leave cards as they are.The Wishlist page has a header
The standalone Wishlist page now opens with a header. On a customer’s own list it carries the list menu, with a lock beside a private list’s name; renaming a list or changing its privacy updates the header, and deleting it returns the customer to all of their saved items. At the end of the header sits an account button: Sign in for a guest, and the customer’s initial for an account, which opens a small menu with their lists, their account page and sign out. In the customiser, Views → Wishlist page → Page header sets the title shown on the all-items view, aligns it left or centred to match your collection pages, and turns the Add all to cart and account buttons on or off. A Share button is there too, off and locked for now: it can only share a single list, and it opens up once the whole wishlist can be shared. In code it’s thepage-header section of ui.listDetailPage, where showShareButton: true already enables it for single lists.Choose the image on product cards
TheproductImage transform picks the image a product card shows, in the drawer and on the Wishlist page. Return any of the product’s images, for example the second one or a flat lay found by its alt text, or an image URL from a product metafield. Return nothing to keep the default: the variant’s image, else the featured image.Switch product card images in the drawer
Turn on Show image toggle for the grid in Views → Saves or Views → List detail (showImageToggle) to give customers a switch between each card’s default image and the one your productImage transform picks, such as model shots and flat lays. Cards open on the default image, and the choice lasts for the session. Rename the switch with productCard.imageToggle in translations.Save button beside the product title
The save button on product cards can now sit beside the product title and price instead of over the image. Set Global → Preferences → Product cards → Save button position to Beside title, orui.productCard.saveButtonPosition to "title". There it shows as a plain icon in the card title colour, filled once saved. Quick buy and badges stay on the image. It applies to every product card in the drawer and on the Wishlist page. The default, On image, leaves cards as they were.Variant select on combined listings
Customers can pick a variant of a product from a Shopify combined listing in the save dialog, quick buy, the product detail view in the drawer and the Notify Me dialog. Without thecombinedListingParent transform, the picker offers the variants of the product the customer is on. With it, the picker also switches between the listing’s products.Quick buy adds saved items straight to the cart
The quick-buy button on a card for an item saved with a variant now adds that variant straight to the cart, instead of opening the quick buy dialog to confirm it. It adds the amount on the card’s quantity stepper when Show quantity input is on, and 1 otherwise. The card then shows as in the cart, and tapping it again takes the customer to their cart. Items saved without a variant still open quick buy to pick one. To keep the dialog for every card, turn on Global → Preferences → Cart → Quick buy → Prompt for variant even when one is selected, or setintents.initiateQuickBuy.promptVariantIfPresent to true. initiate:quick-buy follows the same setting: given a variantId, it adds to the cart and resolves as create:cart-line.Previewing the sign-in requirement covers #swish links
In the customiser, a page you open with a #swish link or a ?swish-intent= URL now follows the Sign-in requirement you are previewing in Global → Preferences → Wishlist experience. Before, it followed your saved setting, so with Require sign-in to view chosen but not saved, the header button asked a signed-out customer to sign in while /#swish still opened the drawer. Live storefronts were not affected.A New badge for recently published products
A custom badge in Global → Preferences → Product badges can now show on products published in the last few days. Pick Product published within as its condition and set the number of days, 30 by default. Call it New to mark your latest arrivals without tagging them: the badge comes off each product by itself once the days have passed. In code the condition is{ type: "published-within", days }; see ui.badges.rules.Custom icons are sanitised before they render
Every SVG inui.icons is now sanitised in the browser before it renders, whatever saved it. Scripts, event handlers, javascript: links and elements that are not SVG are removed. If nothing drawable is left, the built-in icon shows instead. Icons made in the customiser render as before.Product not found in the drawer
When a customer opens a product that has since been deleted or unpublished, for example from a notification about it, the product detail view in the drawer now says Product not found instead of loading forever. Change the text withdrawer.productDetail.productNotFound and drawer.productDetail.productNotFoundDescription in translations.X icon on Saved from cart
The button that removes an item from Saved from cart in the drawer now shows an X instead of a trash can. To keep the trash can, set Global → Preferences → Cart → Saved from cart remove icon to Trash can, orui.cart.savedFromCartRemoveIcon to "trash".Require sign-in for all features
Require sign-in for all features is a new sign-in requirement that asks a signed-out customer to sign in before every action Swish can gate, including any gated in a later release. Today that is saving and opening Swish: a customer who taps save, a header button, a#swish link or any view: intent goes to sign-in instead, and the header button and <swish-drawer> count read as empty until they are back. As under Require sign-in to save, an item saved automatically when a line is removed from the cart still saves. Pick it from Sign-in requirement in Global → Preferences → Wishlist experience, or set features.signInRequirement to "all". See the Account guide for what each setting covers.Greet customers in the drawer header
Set Views → Drawer → Header → Header style to Greeting (headerStyle: "greeting") to show Hi, Sarah at the top of the drawer instead of your logo, using the first name on the customer’s account. Guests see Welcome, or your own text from Guest greeting (guestGreeting). The greeting uses the drawer’s heading style. Reword either default with drawerHeader.greeting and drawerHeader.guestGreeting in translations. See Drawer.Expand a list to the full width of the browser
Turn on Show expand button in Views → List detail to give customers an expand button in a list’s header in the drawer. It widens the drawer to the full width of the browser, and the grid fills the room with more columns, so a long list or a list of large products shows more at once. The footer navigation hides while the drawer is expanded, and the header stays with the list’s share and menu buttons. The drawer goes back to its usual width when the customer collapses it, leaves the list or closes the drawer. The button shows on screens 600px wide and up, where the drawer opens as a side panel. In code it’sshowExpandButton on the list-items-grid section of ui.listDetail. Its screen-reader labels are drawer.listDetail.expand and drawer.listDetail.collapse in translations.Save button animations
Save buttons can play an animation when a customer taps one to save an item: Pulse, Jello or Particles, a burst of small copies of the icon. Pick it under Global → Save button → Save animation, where the preview plays it, or setui.saveButton.animation. Placed save buttons and the hearts in the drawer and on the Wishlist page play the same one, and nothing plays for customers who turn on reduced motion. The default, None, plays nothing.Continue with Shop follows your Sign in with Shop setting
The sign-in callout offers Continue with Shop only on stores with Sign in with Shop turned on in Shopify. With it off, customers see the regular sign-in button.Variant select on product cards
When a product card lets the customer change the variant (enableVariantChange, on by default on the Wishlist page), an item saved without a variant reads Select Size, and its buy button opens quick buy to pick one. The prompt names the product’s first option and is variantSelect.selectOption in translations. In code, swish.state.itemState and useSwishItem expose the saved variant as savedItemVariantId.Close button sits beside the drawer header’s other buttons
Views → Drawer → Header → Show close button (useCloseButton) adds a close button at the end of the drawer header, after the notification and account buttons. To show the close button alone, also turn off Account button and Notification button (accountButton and notificationButton). See Drawer.Notify Me lists only sold-out variants
The Notify Me dialog now offers only variants a shopper can’t buy. Each option lists the values that lead to a sold-out variant, given what is picked in the options before it: pick a colour and the size list narrows to the sizes sold out in that colour. Since everything listed is sold out, values are no longer struck through or marked Sold Out in the dialog. If the dialog opens on an in-stock variant, for example fromcreate:subscription, that pick is cleared and the shopper chooses again. When nothing is sold out, the dialog lists every variant as before.Notify Me asks for the variant with a dropdown
The Notify Me dialog now shows one dropdown per option instead of pills. Until the shopper picks one, the dropdown reads Select an option, which isproductOptions.selectPlaceholder in translations. To keep pills or rows, set Global → Preferences → Notify Me dialog → Variant picker, or ui.notifyMe.variantSelectDisplayType to "pills" or "rows". Your product page’s Variant select display no longer applies to the dialog.Variant select display reaches the drawer and quick buy
Product detail → Product info → Variant select display now applies to the product detail view in the drawer and to quick buy. Both always showed pills before, whatever you chose. If you chose Rows, they now show rows.Link card to product page is one switch for every view
Link card to product page is now only under Global → Preferences → Product cards. Views → List detail no longer has its own switch, so the Global switch decides for every product card in the drawer, including cards in a list. The Wishlist page still always links its cards to the product page. In code, thelist-items-grid sections of ui.listDetail and ui.listDetailPage no longer take a linkToProductPage option, and a value set there is ignored. Use ui.productCard.linkToProductPage or the linkToProductPage transform.Low stock and discount badges
Global → Preferences → Product badges now has a built-in Low stock badge next to Sold out and Sale. It shows when 1 to your number of units are left (5 unless you change it). It reads the selected variant when there is one and the product’s total stock otherwise, and never shows for a sold-out item or a variant selling on backorder. Low stock starts hidden: turn it on with the eye. Swish only fetches stock levels while it is shown. A custom badge can also show when a product is discounted by at least a percentage you choose (Product discount is at least, 20% unless you change it).The text of Sold out, Sale and Low stock is now changed in each of your languages under Global → Translations → Products, so the Badge text field is gone from those three rows. If you entered text there, it showed in every language; after your next save the badge shows its translated text instead, so add your wording under Translations. Inwindow.SwishOptions the new row is { type: "low-stock", max } and the new condition is { type: "discount", minPercent }; see ui.badges.rules.A setup runs on the theme it was set up for
Each setup is tied to the theme it was set up on, by the theme’s own name (for example Dawn), so copies and new versions of that theme keep working. On a theme with a different name, the Swish app embed doesn’t start Swish and logs a[swish] error in the browser console. The customiser still opens on any theme. To use a setup on another theme, choose Duplicate to theme in Settings → Setups; the copy keeps its placements only if the new theme has the same name. The customiser’s top bar shows the setup you’re editing and its theme.Saved items remember their quantity
The product detail view in the drawer opens on the quantity stored on a saved item. Changing it saves to the item, so the same quantity is there the next time the customer opens it, and Add to cart adds that amount. A save made from the drawer keeps the quantity chosen in the input. In code, the newedit:item-quantity intent writes the quantity, and swish.state.itemState and useSwishItem expose it as savedItemQuantity.List cards can show the saved quantity
Turn on Show quantity input under Views → Wishlist page or Views → List detail and each card shows a stepper set to the item’s saved quantity. Add to cart and quick buy add that amount, and the quick buy dialog opens on it. On the customer’s own list a change is saved to the item, so it is there after a reload. On a shared list, or a smart list such as Recently viewed, a change only sets the amount added, and a reload shows the saved quantity again. In code the option isshowQuantityInput on the list-items-grid section of ui.listDetailPage and ui.listDetail, and initiate:quick-buy takes a quantity.The heart on Saved from cart moves the item to the wishlist
Tapping the heart on a Saved from cart card saves the product to the customer’s wishlist in the same quantity and takes it out of Saved from cart. In code,swish.state.itemState and useSwishItem take a quantity option.Items moved from the cart are tagged saved-from-cart
A cart item a customer moves into their wishlist carries the saved-from-cart tag, so you can tell those saves apart in swish.api.items and the REST API. swish.state.itemState also takes a tags option.Style each placed save button on its own
A placed save button can override any Global → Save button setting, including icon, sizes and the Unsaved and Saved colours, and inherits whatever you leave unset. Inwindow.SwishOptions, see the save button design tokens.Translations in the customiser
Global → Translations lists your store’s languages, with your default language first and each other language marked Translated or Needs translation. Open one to change Swish’s text line by line, grouped by where customers see it, with the English beside each line. Leave a line empty to keep Swish’s own text. Your changes reach your storefront when you save. See Translations.Translate Swish into any language
Swish’s text can be translated into languages it doesn’t include, such as French or Spanish. Add your text under that language’s code intranslations. Customers who browse in that language see your translations, and English for anything you leave out.The customiser warns when your theme also configures Swish
If your theme’s Liquid code setswindow.SwishOptions, the customiser now shows a notice under its top bar: Your theme has its own Swish settings. Those settings might conflict with what you configure in the customiser. The notice only informs you. It changes nothing in your theme or your setup, and it doesn’t appear when your theme sets no window.SwishOptions.Choose which badge a product shows
Global → Preferences → Product badges lists your product badges in priority order, and each product shows one: the first badge in the list that applies to it. Sold out and Sale start in the list in today’s order, so nothing changes until you edit it. Drag a badge to change its priority, or hide it with the eye. Add your own badges with no code: each shows when a product has a tag, or when a product metafield has any value, equals a value or contains one. Every badge can have its own background and text colour; leave them blank to use the style from Design → Badges. Sold out and Sale can also take your own text, which replaces the translated text in every language. Swish fetches the metafields your badges name, so you don’t list them undermetafields as well. The list is ui.badges.rules, and the productBadges transform receives the chosen badge in defaultBadges, so a transform can still change or drop it. Sold out and Sale without custom colours still arrive as the same strings as before; anything else arrives as a Badge object.Save buttons come in two looks
A placed save button is now either On image or On page, and each look has its own settings. On image is for buttons over product photos - collection cards and image corners: a dark heart on a white chip, filled once the item is saved. On page is for buttons in the page flow - under Add to cart or in your theme’s button row: a white heart and Save item label on a dark button, sized like your theme’s buttons and rounded by Design → Rounding.Set each look on Global → Save button, where the preview shows the configured button on a light and a dark ground, exactly as a light or a dark theme renders it. Editing one look never changes the other, and Icon style stays shared. A product page placement picks its look with Style: choosing On image turns Icon only on and moves the button onto the product image as an overlay in its top corner, choosing On page puts the labelled button back under Add to cart. Collection placements are always On image. Inwindow.SwishOptions the tokens are ui.design.saveButtonOnImage and ui.design.saveButtonOnPage, replacing ui.design.saveButton and savedIconColor, and a placement carries style: "on-image" | "on-page". A placement that names no style is On page unless it sits on a collection card, so add style: "on-image" to a hand-coded overlay over product images. The hearts in the drawer and on the wishlist page follow the On image settings.Save for later skips items already saved
When a customer removes a cart item they have already saved, Swish no longer offers to save it again or saves a second copy. Instead a toast tells them You’ve already saved this, and nothing is added to Saved from cart. Removing an item that isn’t saved works as before. The new text istoast.alreadySaved in translations, and it is hidden along with the other save-for-later feedback when saveCartLine.showFeedback is false.Saved from cart shows a first-time visitor’s items
A visitor with nothing on their wishlist who removed an item from the cart saw the We’ve saved this for you toast, but Saved from cart in the drawer stayed empty. The item only appeared once they also saved something to the wishlist. It now shows straight away.Pick the unsaved heart colour in the drawer
The hearts in the drawer and on the wishlist page now takesaveButtonOnImageIconColor before an item is saved, just as they already took saveButtonOnImageSavedIconColor once it is. Until now they stayed your primary button text colour, so only the saved half of the pair reached them. Every save button token is listed under ui.design.saveButtonOnImage and ui.design.saveButtonOnPage on the Design page.Preferences are split into rows
Global → Preferences no longer puts everything under one Behaviour row. It now lists Wishlist experience, Saving, Cart, Notify Me dialog and Product cards, each its own collapsible row, and the drawer-or-page choice is labelled Wishlist surface. Nothing to redo: the values are unchanged, they have only moved.Preview a placed save button as saved
A save button placement’s preview now has Unsaved and Saved tabs, like the Save button page, and clicking the previewed button flips it too. Its Saved background and Saved text colour overrides show up in the Saved tab, so you can check the saved look before publishing.Show whole product photos
Product cards, gallery cards and the product detail slider crop each photo to fill its frame, which cuts the edges off non-square photos in a square frame. Set Global → Components → Images → Image fit to Show whole image to fit the entire photo inside the frame instead. The setting isimageFit under ui.design.sizes, and Crop to fill keeps the current look.Notify Me is off by default in the drawer
A sold-out variant in the drawer’s product detail view and in quick buy shows the disabled Sold out button again, not Notify me when available. To offer sign-ups there, setnotifyWhenSoldOut: true on the buy-buttons section of ui.productDetail in window.SwishOptions, and pass the whole default sections array with it, since a sections array replaces the defaults. The Notify Me button placement on your theme’s product page is unchanged.Components have their own screen
The per-component settings that sat at the bottom of Design — drawer width, thumbnails, product cards, product options, gallery cards and form inputs — now live on Global → Components, with each component as its own collapsible row. Nothing to redo: the values are unchanged, they have only moved.The header button matches your theme’s header icons
A Header placement you haven’t styled now looks like the icons beside it: a 44px button around a 20px heart drawn in your header’s text colour. It used to borrow the Save button’s icon colour, which is white for a heart over product photos — and invisible on a light header. Set Icon outline colour on the placement to pick something else.The saved-count badge is centred on the heart’s corner, with no white ring, and stays there when Show text puts a label beside it — it used to hang off the button’s edge, 11px from the heart, and drift further the longer the text. Badge position still picks the corner and the two Badge offset sliders still nudge it, but they now start from the heart, so a badge you had dragged into place is worth a second look. The customiser preview draws the badge as the round shape the storefront shows, and a numericstatusIndicatorFontWeight set through swish.placements now applies instead of being dropped.Add to cart is back by default
A store that has never written anaddToCartButton transform shows Add to cart on the drawer’s product detail again, and quick buy on Home featured collection rows — both had been missing since April. Hide them per product with the addToCartButton transform, or turn the product detail buttons off for the whole store with the eye toggle on Views → Product detail → Buy buttons.The drawer header shows your store name
The drawer opens with your store’s name across the top, and follows it if you rename the store. Set a Title or a logo under Drawer → Header to show something else instead.Save from cart catches every removal
Removing an item didn’t always offer to save it — on some themes, and when another app was reading the cart at the same time. Every removal is now caught.The Home view is now For You
The drawer’s first tab reads For You in every language Swish ships, and the customiser lists the view as Views → For you. The rail on Saves that holds Recently viewed and Saved from cart is now Smart Lists, so no two surfaces share a name. Nothing to redo: the underlying settings are unchanged, and a translation you’ve overridden still applies.Remove items from Saved from cart
Each Saved from cart card in the drawer, on For You and in the list itself, now has a trash button above the heart that removes the item once the customer confirms. The heart saves the product to the customer’s wishlist, and the card stays in Saved from cart until they remove it. Until now there was no way to take an item out of Saved from cart.The customiser no longer signs you out after your laptop sleeps
The customiser sometimes showed Session expired when you came back to it after your laptop slept, after the tab sat in the background, or after a brief network drop, even though your session was still valid. It now renews its sign-in as soon as you return to the tab, retries while the connection comes back, and when a save meets an expired sign-in it renews and saves again instead of stopping. Session expired now appears only when the session has really ended, and reopening the customiser from Swish admin still starts a new one.Notify Me confirms the sign-up
After a shopper leaves their email, the dialog now stays on You’re on the list with the address it went to and a Done button, instead of closing before anyone could read it. Global → Preferences → Notify Me dialog gains a third mobile-only switch, Full height on mobile, which takes the dialog to the top of the screen. In code,fullHeight on ui.notifyMe.Saves drops the empty “For You” rail
A shopper with nothing saved no longer sees an empty For You rail, or a grey card that never resolves when the lists request fails. A rail with nothing to show is hidden, and the one still loading now carries its name.Colors grouped by role
Design → Colors is now grouped into Text, Buttons and Surfaces, and badge colours have their own Badges section. Swish’s own save hearts in the drawer and wishlist page now follow the Save button colours, so the two separate heart-background fields are gone.Buttons recover from a failing handler
A custom intent handler that throws no longer leaves a drawer or card button spinning. The button settles and can be tried again.Build your own wishlist page or drawer
swish.state could already power a custom save button and a header badge, but a custom page of saved items meant calling the API yourself, paginating by hand, and wiring up every event that could change the grid. Four new state helpers take that over. listContext(window.location) reads which list a page is about from the same URL parameters share links and the view:list intent already use. lists() gives you the customer’s named lists plus Saved from cart and Recently viewed for tabs. items(context) is the paginated collection itself: it drops an item the moment it’s unsaved, prepends a fresh save, patches a changed variant, and refills after sign-in, whether the change came from your UI or ours. product(ids) resolves one card’s product data lazily, sharing the built-in UI’s cache and combined-listing handling.The simplest custom page is a listContext feeding items, plus product and the existing itemState per card. A richer drawer writes one context signal per tab and reuses a single collection. Actions stay on intents, so there is nothing new to learn there. Every helper now has dispose(), including itemCount(), which previously kept refetching after its consumer went away. See the State reference for the full API and two end-to-end examples.Notify Me on sold-out products
When a product is sold out, shoppers can sign up to hear when it’s back. Notify me when available takes the place of the theme’s disabled button, and the dialog collects a size and an email address. A product with sizes still in stock is untouched — the theme’s buy button stays where it is.Global → Preferences → Notify Me dialog adds two mobile-only switches, both off by default: Flush to edges on mobile runs the dialog edge to edge against the bottom of the screen, and Taller on mobile gives it the drawer’s height. In code,flush and tall on ui.notifyMe.Resize the drawer’s footer menu labels
The Home / Saves / Lists labels along the bottom of the drawer were fixed at 10px, which is small next to a bold storefront font and smaller still once a translated label runs long. Views → Drawer → Footer now has a Text size slider: 1× is what you have today, and you can take it anywhere from 0.8× to 2×.It’s a multiplier rather than a pixel value, so if you’ve already set your ownnavLabelFontSize the slider scales from your size, not ours. Labels only — the icons under Show icons keep their own size, so the bar’s height and alignment stay where your design put them.In code it’s fontScale on the drawer-footer section of ui.drawer, and it drives a new --swish-theme-nav-label-font-scale theme token.Point the account button at your own account page
The account icon in the drawer header always opened Swish’s profile view, and the only way out of that was to hide the button altogether. Views → Drawer → Header now has an Account button opens dropdown: Swish profile (the default, so nothing changes for anyone), Shopify account page, or Custom URL for a page of your own.Pick Shopify account page and Swish works out the right address for your store. Custom URL takes anything else, like/pages/my-account or a full web address.It covers the header icon only. The footer’s Profile tab and the Account link placement are separate controls and still open the Swish profile view — turn those off too if you want customers off it entirely.Notify Me on sold-out variants
A sold-out variant used to be a dead end: a greyed-out “Sold Out” and nothing to do about it. Now the shopper can ask to hear when it’s back, and you keep the sale you were going to lose.Two places it shows up. Inside Swish, Views → Product detail → Buy buttons has a new Offer Notify Me when sold out switch which turns that disabled button into Notify me when available in the drawer product detail and in quick buy. It’s on by default, so this one arrives switched on for every store — turn it off there if you’d rather keep the disabled button. And on your own product page there’s a new Notify me button placement under Placements → Product detail, sitting in the same list as the save button: pick it from the Type dropdown when you add a placement. That half is opt-in — nothing appears until you add it.The placement is the interesting half, because it works with your theme rather than around it. Point it at your buy-button row — the Target field suggests.product-form__buttons, which is Dawn’s — and Swish hides the element you pointed at only while the selected variant is out of stock. Switch to a variant that’s in stock and your own button comes back exactly as it was, with its own styling and its own behaviour. Nothing is replaced, so nothing is lost. What you point at is what gets hidden, so aim at the button row itself rather than the form around it.Either way, tapping it opens the standard Swish modal: product thumbnail, a Product / Option / Option breadcrumb, an email field and a signup button. A signed-in shopper’s address is already filled in; a guest types one and can subscribe without an account. Submitting confirms inline and closes itself, and the signup lands in your subscriptions where the back-in-stock notification picks it up.In code the placement is element: { name: "notify-button" } with mount: { mode: "after" }, the in-drawer switch is notifyWhenSoldOut on the buy-buttons section of ui.productDetail, and there’s a new create:subscription intent to open the modal yourself. swish.api.subscriptions is now exposed too — list, create, findById, updateById, deleteById. All the copy is translated in all six languages under notifyMe.* and buyButtons.notifyMe.Content blocks on Saves and Lists
Content blocks are no longer a Home feature. Views → Saves and Views → Lists now carry them too, with everything Home has: Add content block under the section list, up to three per view, a delete control on each, the Visible to targeting group, and a drag grip on every row.Which matters because Saves and Lists are where a shopper has already told you what they want. A block above the saved-items grid reaches someone with your product in mind and nothing in their cart — closer to the sale than the same message on Home, and closer still if you point it at a tag. Each view keeps its own blocks, so the offer on Saves can be a restock nudge while Lists gets the account prompt.Both views ship one block, switched off, seeded just above their grid. Drag it wherever you want: on Lists a block can sit either side of the lists themselves, and on Saves it can go above or below the grid. The All Items screen is the saved-items grid on its own, so it drops content blocks the same way it drops the lists sliders.Nothing about an existing block changes, and the targeting rules are identical across the three views — see Content blocks for the options in full. In code it’s acontent-block section of ui.saves or ui.lists, taking the same title, body, image, link and visibleTo as on ui.home. If you’ve saved either view before, your existing sections are kept and the new block is added above the grid.Show a content block to only some shoppers
Home now carries a content block, and you can point it at a slice of your customers instead of all of them. Under Views → Home → Content block there’s a new Visible to group: Shoppers picks Everyone, Signed in only or Signed out only, and Customer tags takes any Shopify customer tags you use —VIP, Loyal Customer, whatever your store already tags on. A shopper carrying any one of the listed tags sees the block; everyone else doesn’t.So the segment-only message you’d otherwise send by email can live in the drawer: tag your best customers VIP, write the offer once, and only they get it. The block ships switched off, and the eye toggle still hides it from everyone regardless of who it’s aimed at.Home also takes more than one block now — up to three. Add content block sits under the section list, each block has a delete control, and every section has a drag grip, so you can put a promo above your saved items and a VIP offer below them. If a shopper matches two blocks they see both, in the order you’ve arranged them.Tag matching ignores case, so VIP finds a customer tagged vip. Only customers have tags, so a tag list also means signed in — pairing one with Signed out only shows the block to nobody. The preview applies the rule as your shoppers will see it, the same way it already respects the eye toggle, so a block aimed at someone the preview isn’t drops out of view — it stays in the Sections list, where you edit it.In code the setting is visibleTo: { audience, customerTags } on a content-block section of ui.home. Headless stores need to pass context.customer.tags themselves; on Shopify themes the app embed handles it.The “in cart” button takes shoppers to their cart
Tap a product that’s already in the cart — the quick buy button on a card, or Add to cart on the product detail view — and Swish now takes the shopper to their cart instead of doing nothing. By default it navigates to the cart page.Stores that open a slide-out cart drawer instead of a cart page can point Swish at it: Global → Preferences → Behaviour → Cart has a new Cart drawer selector field. Enter the CSS selector of the element that opens your theme’s cart drawer (for example#cart-icon-bubble) and Swish clicks it. Leave it blank — or if the selector is invalid or matches nothing — and Swish falls back to the cart page, so the button is never a dead end. A Send shoppers to their cart switch turns the whole behaviour off.In code the settings are ui.cart.navigateOnInCart: boolean and ui.cart.drawerTrigger: string.Card layout for saved items
Three views now have a Layout setting: Views → Saves (the saved-items grid), Views → List detail and Views → List detail page. Leave it on Gallery and nothing changes; switch it to Card and each saved item gets a full-width row instead of a grid tile: the image on the left, and on the right the vendor, product title over two lines, price, saved variant and an Add to cart button.Card layout is for stores where the grid tile is too cramped to sell — more room per product means a badge and a real call to action can sit side by side instead of competing for the same 150 pixels.The Saves setting also drives the All Items screen its heading links to, since both read the sameall-items-grid section. The lists sliders above the grid are unaffected.A few things the layout decides for you. The product image renders square rather than following your Global → Design → Image card aspect ratio: a portrait image makes each row half again as tall and undoes the point of the layout. On Saves and in the drawer’s list detail, Add to cart is always on in card layout — neither view exposes a buy-button switch to turn on — though it still only appears if you’ve supplied the addToCartButton transform. On the standalone list page the existing Show buy button switch keeps working, and Desktop columns still applies, but card rows are wide: 1 or 2 reads best, and mobile is always a single column.The new vendor line has its own Show product vendor switch, on by default, and applies to card layout only — the gallery tile is unchanged. In code the settings are layout and showVendor on the all-items-grid section of ui.saves and on the list-items-grid section of ui.listDetail and ui.listDetailPage.Open your saved items on their own
The heading above the saves grid is now a link. Tap the chevron or the heading text and the saved items open on a screen of their own, headed All Items and without the Your Lists and For You sliders above them; the drawer’s back arrow returns to Saves, and the Saves tab stays selected throughout.It’s the same grid, reading the sameall-items-grid options you set for the saves view, so anything you configure there applies on both screens. The chevron only appears where it has somewhere to go: a store whose saves view is already nothing but the grid — single list mode, or both sliders hidden — doesn’t get one.All Items is translated into every built-in language (Alle Artikel, Kaikki tuotteet, Все товары, Alla artiklar, Wszystkie produkty). Want different wording? Override saves.allItems under translations, per language.Sign in prompt on Saves and Lists
Signed-out shoppers now see the sign-in callout on the Saves and Lists views, not just Home. It sits above the content, so a guest’s own saved items and lists stay visible underneath — these are the two views where a shopper has something to lose by staying a guest, and until now neither said so.Each of the three views has its own Message field under Views → Home / Saves / Lists → Sign in, so you can make a different case in each place — “Sign in to keep your saves on every device” on Saves, something else on Lists. Leave a Message empty and that view shows the default copy, translated into every supported language. The section’s eye toggle hides it from that view alone.In code the setting isoptions.message on the sign-in section of ui.home, ui.saves and ui.lists; a t:-prefixed value resolves as a translation key, so your own copy can be translated too.Item count stays put while it refreshes
swish.state.itemCount() and useSwishItemCount() used to report loading: true on every refetch, so a badge that hid itself while loading would blink empty each time a customer saved or unsaved. loading is now the first fetch only. Mid-session refreshes set refetching: true instead, and the last known count stays on the signal until the new number lands.Prices follow your currency formatting
If your store hides decimals under Settings → General → Currency formatting, Swish now hides them too — on product cards, the product detail view, quick buy, order totals, order line items and price-drop notifications. Previously every price showed cents regardless, so a storefront reading$11,500 had a drawer reading $11,500.00.Swish reads the decimal part of your format only. The currency symbol, where it sits and the thousands separator still come from Swish’s own per-currency formats, so a format like $ {{amount_no_decimals}} renders $11,500 rather than $ 11,500.Headless setups pass this themselves as context.moneyFormat; on Shopify themes the app embed handles it.Turn off quick buy on product cards
Global → Preferences → Product cards has a new Show quick buy button switch. Turn it off and the floating cart button disappears from every product card — the saves grid, both list detail views, product recommendations and featured collections — while Add to cart on the product detail view stays exactly as it is.Until now the only way to remove those buttons was theaddToCartButton transform, which is per product rather than per view, so switching it off took the product detail button with it. Views that have their own Show quick buy button toggle can still hide it in just that view; they can’t show it while the global switch is off.In code the setting is ui.productCard.showQuickBuyButton: boolean.The wishlist page says “Wishlist”
Your standalone wishlist page used to head its saved items All Items — multi-list wording on a page that holds one wishlist. It now reads Wishlist, translated into every built-in language (Wunschliste, Toivelista, Список желаний, Önskelista, Lista życzeń). Opening the page for a specific list still shows that list’s own name.Want different wording? Overridedrawer.listDetail.allItems under translations, per language.Require sign-in to save, or to open Swish at all
Saving works without an account by default and still does — but a store that treats a saved item as the start of a customer relationship can now ask for sign-in first.features.signInRequirement takes "save" to gate saving, or "view" to gate opening Swish.A signed-out shopper who hits a gated action doesn’t get silence. Swish runs the same initiate:sign-in flow as the drawer’s account button — it confirms first, then hands off to your store’s sign-in page. What they were doing travels with them as a return URL — the product, variant, quantity and tags of the save they came for — so it happens on the way back instead of being lost to the redirect.The two settings gate different halves. "save" covers the shopper’s own save and nothing else: the drawer stays browsable, and an item saved automatically when a line is removed from the cart never prompts. "view" is the stricter one — anything a shopper taps to open Swish, whether a header button, a #swish link or any view: intent, goes to sign-in instead, including the redirect to the classic wishlist page. Saving from a product page still works for guests under it. One way in stays open: the standalone wishlist page mounts from its own URL rather than from an intent, so a signed-out shopper who navigates straight to it still sees their saved items.In code the option is features.signInRequirement: "none" | "save" | "view", defaulting to "none". See the Account guide for the full description.Sign in with Shop fix
Sign in with Shop now works reliably where it previously failed to sign customers in in some cases.Swish opens from your account link
Placements → Header has a new Account link placement. Add it and your theme’s account link opens Swish instead of the Shopify account page, keeping your theme’s own icon and styling and optionally showing the customer’s saved item count as a badge. Opens picks which view it goes to — point it at Profile and signed-out customers go to sign-in instead.Swish can open on any view, not just Home
Global → Preferences → Behaviour starts with a new Default view dropdown — Home, Saves, Lists, Notifications, Orders or Profile — so a store running Swish as a pure wishlist can put Saves in front of every shopper without touching its theme.view:home now means “open Swish” rather than “open the Home view”, so a header button, a swish-intent="view:home" button, a #swish link and a ?swish-intent=view:home URL all land on your default view as they are. It is also the drawer’s root: Back from a product, a list or any other view returns to it instead of to Home, and the save toast’s View action follows it too.The Home view stays reachable from the footer Home tab. In code the setting is ui.defaultView: "home" | "saves" | "lists" | "notifications" | "orders" | "profile".Phone number and SMS consent on the Profile view
The Profile view now has an editable Phone field, and the SMS toggle under Marketing consent is always shown rather than appearing only for shoppers who already had a number on file. A number entered alongside the toggle is saved in the same request, so a shopper can add their phone and opt in at once. Numbers are expected in international format (+353871234567), and switching SMS on without a number asks for one instead of failing silently. A number already saved on the account can’t be removed from this view yet.Button width and height can use px or %
A placement’s Design → Width and Height now take a number with a switchable unit, so a Save button can be a fixed 300px or stretch to 100% of its container. Leave either blank to keep the button’s own size. In code the design value carries its unit as a string ("300px", "100%"), and a bare number is still read as pixels, so existing configs keep working.One list instead of many
Global → Preferences → Behaviour gained an Allow multiple lists setting, on by default. Turn it off and Swish stops offering list management while keeping the drawer: saving still shows its toast, but the toast’s action opens your Default view instead of the list picker, unsaving skips the picker, and the list sections on Home and Saves plus the Lists tab in the drawer footer are hidden. For you lists are unaffected — they are smart lists with no create-or-manage actions.In code the setting isui.wishlist.multipleLists: boolean.Classic wishlist page, instead of the drawer
Global → Preferences → Behaviour → Wishlist experience is a new dropdown: Drawer (unchanged) or Classic Wishlist page, which replaces the drawer entirely. Anything that would have opened the drawer — a header button, a#swish link, any view: intent — sends the shopper to your standalone wishlist page at context.routes.listDetailPagePath (/apps/wishlist unless you set it), carrying a list-id through when one is given. Multi-list is off with it, so the save toast no longer offers Add to list and unsaving from a save button no longer asks which list to remove from — your Confirm before unsaving preference still applies.In code the setting is ui.wishlist.experience: "drawer" | "classic-page".Save for later can go to the wishlist
Global → Preferences → Behaviour → Save cart line gained a Save destination setting. Leave it on Saved from cart for the current behaviour, or pick Wishlist to have items removed from the cart saved as ordinary wishlist items — a “move to wishlist” instead of a separate list. Picking Wishlist hides the now-empty Saved from cart section on Home, and the For you section on Saves along with Recently viewed.Custom CSS can now style the button itself
A placement’s Custom CSS is still applied to the storefront page — so the documented[swish-placement-element="…"] selector and parent selectors like .product-card:hover [swish-placement-element="…"] keep working — but it is now also adopted into the button’s shadow DOM. That means :host and the component’s internal selectors (such as .button) reach the button itself, which page-level CSS can’t.Per-placement Breakpoint overrides have been removed. Existing thresholds are preserved on save, so nothing you configured previously is lost.Save button settings
Save buttons now have their own settings card under Global → Save button. It sets the icon (heart, bookmark or your own SVG) and, for the unsaved and saved states separately, the icon thickness, size, fill and outline colour plus the background behind it. Those values are the defaults for every save button on your storefront — product pages, collection cards and the header link — and each placement can still override them in its own Design section.Save buttons no longer take their look from the standard button’s style, fill and size. Those selects still win when you set one, but they now default to Inherit. A save button created throughswish.ui.createElement("save-button") inherits the same way: it renders with your Save button settings instead of the solid primary button it used to get — and with a transparent background until you set those settings. Save buttons also render their own save icon id rather than the shared heart, so restyling the save button no longer changes every other heart in the UI.Save buttons find their product
A placed save button resolves the product it acts on from the element it is attached to. When that element carries no product reference — a card’s image wrapper, or a product page’s button row — it now looks further: a product-page button reads the page itself, and a collection-card button walks to that card’s own product link. Buttons that previously rendered but did nothing when tapped now save the right item.Placement fixes
Each placement’s generated stylesheet is now scoped to that placement even when it has no id, so placements no longer overwrite one another’s layout CSS — previously a second placement could silently strip the first one’s positioning. Overlay placements position against the element they are mounted into rather than its parent, so an anchor corner lands on the box you targeted. Per-placement saved background and text colours, and the corner radius, now apply to the storefront; they were previously accepted and ignored.Notifications honor “Link card to product page”
Notifications in the drawer now follow the same Link card to product page rule as product cards: with it on, tapping a notification navigates to the product page; with it off, it opens the in-drawer product view as before. Because a notification only carries a slimmed-down product, a transform that reads storefront-only fields (such asproduct.metafields) falls back to the in-drawer view for that row rather than failing.Header button gets a text label and its own Design section
The header button can now show a label beside the heart: turn Icon only off and set Text. Its new Design section sets what the button actually reads — icon size, weight, colour and spacing either side, plus the saved-count badge’s colour, text colour, size, corner and offset — and a blank field inherits your Save button settings. The oldbackground, color and radius tokens are gone; no header stylesheet ever read them, so they saved and published while rendering nothing. If you set them through swish.placements.create, use iconColor for the icon and statusIndicatorBackground for the badge.Two badge fixes come with it: the badge no longer lands in the middle of the button when no icon size is set, and its text colour now applies. The badge is positioned from a corner of the button rather than relative to the icon, so a placement relying on the old icon-relative position may need its offset nudged.Hidden placements stay hidden
The eye control on the Placements list now works: a hidden placement stops rendering on your storefront and keeps all of its settings, so you can un-hide it later. It previously kept rendering.Mini menu links follow the shopper’s language
The Home view’s mini menu now offers four ready-translated link titles — Contact us, Shipping, Returns and FAQs — in every language Swish supports. Pick one and each shopper sees it in their own language; pick Custom and your own wording is shown to everyone exactly as you typed it. Links you have already set up keep the title you gave them; re-pick one from the dropdown to translate it.Sign in with Shop in the sign-in callout
The sign-in callout now offers Sign in with Shop to buyers Shop already recognizes, so they can authenticate in one tap instead of being sent to the classic login page. Everyone else sees the existing sign-in button exactly as before.Shop Pay and reorder links point at your store again
The Shop Pay button on the product detail view and the “order again” links in order history built their URLs against a malformed host, so buyers who tapped them landed on a browser error page instead of your store. Both now resolve to the correct storefront domain, including on localized storefronts served from a locale path such as/en-gb.Orders and profile load for every signed-in customer
Signed-in customers now see their orders and profile in the drawer even before saving their first item. Previouslyswish.api.orders and swish.api.profiles.getProfile() returned empty until the customer had a Swish profile.Enrich saved items with render-ready product data
Building a custom wishlist page previously meant loading saved items, then callingswish.storefront.loadProduct() once per item to fetch its Shopify product data - and reimplementing combined-listing handling yourself. The new swish.storefront.loadResolvedProduct(args) returns a single product in a render-ready shape, transparently resolving combined listings the same way the built-in Swish UI does.To build a wishlist page, resolve your saved items concurrently - product fetches are cached individually (repeat views and products shared across lists come from cache) and concurrent cache misses are automatically coalesced into batched Storefront requests, so a Promise.all over your items doesn’t pay one round-trip per item.Reliable redirect after sign-in
Theinitiate:sign-in intent now normalizes its returnTo value to a same-origin relative path before redirecting to the customer login page. Shopify rejects an absolute return_to, so passing a full URL previously stopped customers from being sent back to where they started after signing in. Relative paths are unchanged, and cross-origin targets fall back to the storefront home page.TranslationsAPI
Translate variant option labels
Variant option labels (for exampleSize or Color) come from Shopify and were shown as-is. You can now translate or rename them per language by adding overrides under the optionName. prefix, followed by the exact option name from your Shopify admin (case-sensitive):API client defaults to the 2026-07 version
The unpinned@swishapp/api-client entry point (and the types re-exported from @swishapp/sdk) now resolves to the 2026-07 API version, up from 2026-04. Version-pinned imports like @swishapp/api-client/2026-04 continue to work unchanged.Polish language support
Swish now ships Polish (pl) translations. When a storefront’s active language is Polish, the Swish UI — buy buttons, lists, notifications, orders, and profile — renders in Polish automatically, instead of falling back to English.Undo saving from cart
Whenintents.saveCartLine.confirm is disabled (the default), the feedback toast shown after a cart item is saved now includes an Undo action. Pressing it removes the item from the saved-from-cart smart list. Set intents.saveCartLine.showFeedback to false to disable the toast (and the undo action) entirely.swish.api.smartLists.removeItem
A new SDK method removes an item from a smart list:"recently-viewed" or "saved-from-cart" and returns the removed item.Configurable toast duration
A newui.toasts.autoHideDuration option controls how long toast notifications stay visible before auto-dismissing, in milliseconds:5000 (5 seconds), which now applies to all toast variants — compact toasts previously dismissed after 2 seconds. Set 0 to disable auto-dismiss.Configurable thumbnail aspect ratio
A newthumbnailAspectRatio design token controls the image ratio for notification cards, toast notifications, and order item thumbnails. Set it under ui.design.sizes:1 / 1 (square), matching the previous behaviour.Global default for linkToProductPage
A new linkToProductPage transform lets you control whether product cards link to the PDP globally, or per product, without configuring each section separately.true to make cards navigate to the PDP; return false (the default) to keep the in-drawer product view behavior. The transform is the global fallback — section-level linkToProductPage options still take precedence when set.linkToProductPage is also now exposed as a configurable option on all three product card sections (all-items-grid, list-items-grid in the drawer, list-items-grid on the standalone list page) so all views are consistent.List detail page mounts on #wishlist-page
The list detail page now mounts by replacing a #wishlist-page host element on init. On Shopify themes the /apps/wishlist app proxy page provides this host automatically; headless storefronts (Hydrogen, Next.js, or custom storefronts) should add <div id="wishlist-page"></div> themselves. See List detail page.BreakingPlacementsTranslationsCustomization
Placements API moved to swish.placements
The imperative placements API now lives at swish.placements, alongside the other top-level SDK namespaces (swish.intents, swish.query, …), instead of under swish.dom:swish.dom.createPlacement(spec)→swish.placements.create(spec)swish.dom.placements→swish.placements.list
placements option passed to createSwish({ ... }) is unchanged.Built-in translations for more languages
Swish now ships with built-in translations for German, Finnish, Russian, and Swedish, in addition to English. Swish loads the locale matching your storefront’s active language and falls back to English when a language isn’t built in.Toast notifications and other SDK-triggered feedback are now localized too, so the entire UI follows the active language. You can still override any string per language. See Translations for the full key reference, or email support@swish.app to request another language.BreakingCombined listingsTransformsCustomizationProduct cards
Combined listings in the variant selector
The variant selector now handles Shopify combined listings. When a customer opens it on a child product, Swish loads the parent in the background and renders the full set of options across all siblings. As the customer’s selections resolve to a variant on a different child, the active product switches automatically.Merchants opt in via the newcombinedListingParent transform - typically by storing the parent’s GID on each child product as a metafield:Hide options in the variant selector
A newhideOption transform hides individual options from the variant selector. The option is locked to its first-available value, and the remaining visible options still reflect availability against that value. Common use: combined listings where one option (e.g. "Color") drives the underlying product - hiding it prevents customers from accidentally switching products mid-flow, especially when saving from a collection card.Metafields are now a nested record
Breaking.product.metafields and variant.metafields previously surfaced as an array of { namespace, key, value } objects. They now expose a nested record keyed by namespace, then by key:Before:metafields.product or metafields.productVariant is pre-seeded (as {} when no values exist), so you only need optional chaining at the namespace level for namespaces you didn’t declare.More product-card knobs on list and saves sections
Filled the inconsistencies inlist-items-grid and all-items-grid so the same product-card options are reachable from every section that renders cards.showVariantTitle— now configurable in bothlist-items-gridvariants (drawer + standalone page). Was hardcodedtruebefore. Default staystrue.showBuyButton— now available on the drawer’slist-items-gridand onall-items-grid(savesview). The standalone page already had it. Defaultfalsein the new locations to preserve current behavior. Distinct fromshowQuickBuyButton(the floating button on the card image);showBuyButtoncontrols the solid button beneath the card.hideCompareAtPrice— new across all three schemas. Hides the strike-through compare-at price on cards so only the active price renders. Defaultfalse. Pairs naturally with theproductPricetransform for stores that suppress original pricing entirely.linkToProductPage— now surfaced on all three schemas. Defaults preserve current behavior:trueon the standalone list page (hard navigation to PDP),falsein the drawer’slist-items-gridand inall-items-grid(drawer cards open the in-drawer product view via intent). Flip totruein drawer contexts when you want native navigation instead.
BreakingDeclarative API
New <swish-save> and <swish-drawer> custom elements
The HTML attribute API for declarative save buttons and drawer triggers has been replaced with two custom elements. Markup is shorter, state lives on the element where CSS can target it via standard [state="..."] selectors, and labels compose through nested children instead of per-state attributes.Removed: swish-item-state, swish-item-label, swish-item-label-unsaved/-saved/-saving, swish-item-match, swish-item-context, swish-item-count, swish-product-id. Removed: swish.dom.createElementLocator from the public API.Before:List detailCustomizationTransforms
Configurable list detail views
The list detail view (the screen that opens when a customer taps a list) is now configurable like every other view, with sections underui.listDetail. The same section type also drives the standalone full-page list detail under ui.listDetailPage, so both surfaces share one schema.desktopColumns for the grid width and showBuyButton for whether each card carries a buy button.If you were configuring the standalone page through ui.fullpage.listDetail.*, move those options under ui.listDetailPage.sections[0].options. The old shape no longer works.Custom price display per product
A newproductPrice transform lets you replace or hide the price per product, based on tags, metafields, or anything else on the product. Common uses: “Call for price” on B2B SKUs, hiding price entirely on made-to-order items, or pulling a custom label from a metafield.undefined to render the default price, false to hide the price entirely, or a string to replace it. The transform runs everywhere a price is shown except notifications and order line items. Custom strings inherit the default price typography and pick up .product-price-custom / .price-custom classes for further styling.Renamed product transforms
The product-scoped transforms now share aproduct prefix so the context is unambiguous next to the existing variantTitle and optionValues:title->productTitledescription->productDescriptionbadges->productBadges- (new)
productPrice
transforms config when you move to the new version.Save buttonsPerformance
Smoother, faster save buttons
Save buttons across the storefront feel snappier in this release. Pages with lots of save buttons - collection grids, search results, the drawer - now make far fewer API requests, and the button no longer flashes back to “unsaved” for a split second while a save or unsave is in flight.Product-level save state on collection cards
Save buttons now have an optionalmatch setting. With match="product", the button shows as saved whenever the customer has saved any variant of the product - useful on collection cards that render a default variant but should reflect the product’s overall save state.useSwishItem React hook. The default behavior is unchanged.React: simpler save state for headless stores
useSwishItem is easier to use on headless and Hydrogen stores. You can pass product, variant, or item IDs straight from your data layer and the hook handles the rest, including callbacks for tracking saves and unsaves.Theme embed tracks the latest SDK
The Shopify theme app embed now loads the latest stable SDK by default. Stores pick up new releases automatically without re-saving the embed block.PlacementsProfileHomeCustomization
Placements
A new SDK feature for inserting Swish elements (Save button, drawer trigger) anywhere in your storefront without editing theme templates. Placements use DOM observation to mount automatically when matching elements appear, and survive theme re-renders.Declare placements upfront inSwishOptions:swish.dom.createPlacement(spec). Each placement returns { mount, unmount } so you can control them programmatically. See the Placements reference and the customization guides for product detail, collections, and header placements.Customer profile
The drawer now includes a full profile view where customers can edit their account details, manage addresses, set notification preferences, and add their birthdate.The view uses the newprofile-form section under ui.profile.sections and the view:profile intent. The form integrates with both new and classic Shopify customer accounts and respects locale settings for address formats.Featured collection on home
A newfeatured-collection home section displays products from a Shopify collection in a horizontal slider on the drawer home screen.handle is the collection handle from Shopify. Products are loaded via the Storefront API.Drawer header customization
The drawer header now supports a few new options to fit a wider range of theme designs:useCloseButton- replace the account button with a close button (useful for mobile/full-screen drawers)accountButton- toggle the account button in the headernotificationButton- toggle the notification icon in the headerlogo.urlandlogo.altText- display a logo image in the header
Hide Add to Cart with a transform
A newaddToCartButton transform lets you conditionally hide the Add to Cart button per product, for example for made-to-order items, pre-orders that aren’t yet available, or B2B-only SKUs.false to hide the button on a given product; the default is true.Notification indicator on the main menu
The notification icon in the drawer footer now shows an alert dot when there are unread notifications, making it easier for customers to see updates without opening the drawer.Bulk add to list after in-drawer creation
When a customer creates a new list from inside the drawer, the bulk add-to-list screen now opens automatically so they can populate the new list in one flow instead of returning to it manually.Auto-save from cart fixes
Cart change tracking is now keyed on Shopify line item keys instead of variant IDs, fixing a class of duplicate-save and missed-save issues on stores that attach custom line attributes. Removed items are tracked deterministically across consecutive cart updates.GalleryQuick BuyCustomizationIntents
Gallery view for lists
Lists can now be displayed in a gallery layout with a newGalleryCard component that renders list items in a visual grid. The gallery view is available as an alternative to the standard list layout in both the lists overview and list detail views.Intent renaming
Navigation intent names have been updated fromopen:* to view:* to better reflect their purpose. For example, open:drawer is now view:drawer, and open:list is now view:list. Update any custom intent references in your SDK configuration.Quick Buy and Save flows
A new save-first workflow lets customers save an item to their list immediately, then update the variant afterward. This includes a quantity input modal for add-to-cart confirmation with variant selection. The Quick Buy flow also supports adding items to cart directly from the list.Configuration options:quickBeforeVariantPrompt- enable the save-first, select-variant-later flow- Quantity input modal appears when adding to cart from a list item
Product option improvements
Single-value product options are now hidden automatically to reduce clutter in variant selectors. Variant selection logic has been improved to better determine the selection journey based on product attributes and metafields.Custom content blocks
You can now add custom content blocks to the Swish drawer using thecontentBlocks option, enabling merchant-defined content such as banners, messaging, or promotional sections within the drawer interface.Empty state improvements
Empty states across the drawer have been redesigned with clearer calls to action and better visual presentation when a customer has no saved items or lists.Clickable section headers
Section headers on the drawer home screen are now clickable, allowing customers to tap the header text to navigate directly to the full section view.Configurable menu text
The menu button text is now configurable through SDK settings via themenuText option, allowing merchants to customize the label (e.g., changing “Wishlist” to “Favorites” or “Saved Items”).Admin PDP visit
Admins can now navigate directly to a product’s storefront page when selecting an item from a list, making it easier to verify product details.Smart listsSharingTranslationsCustomization
Smart lists
A new system for auto-generated, read-only lists that populate based on customer behavior. Smart lists appear as horizontal product rows on the drawer home screen with a “View all” link to a full paginated detail view.Recently Viewed - Automatically tracks products a customer has viewed on the storefront. Data is tracked server-side and fetched via the Smart Lists API.Saved from Cart - Items removed from the Shopify cart are automatically saved to this smart list. Read-only - items are managed automatically based on cart activity.Auto-save from cart
When a customer removes an item from their Shopify cart, it can automatically be saved to their list.The SDK intercepts Shopify Ajax API responses to/cart/change endpoints. When items are removed, the SDK extracts the product ID, variant ID, quantity, title, and image from the cart change event, and saves the item with source: "cart".You can optionally show a confirmation toast before saving (“Save this for later?”) and a success toast after (“We’ve saved this for you”). Both can be toggled independently.Configuration options:intents.removeCartLine.saveCartLine- enable or disable the feature (default: off)intents.saveCartLine.confirm- show confirmation before saving (default: off)intents.saveCartLine.showFeedback- show success toast (default: on)intents.saveCartLine.afterComplete- optional callback after saving completes
List sharing
Customers can share their lists via a public link.- Share is a permanent action in the list menu and is also accessible from the list detail view header
- If the list is not already public, access is automatically set to public before sharing
- On mobile, uses the native share dialog. On desktop, copies the share URL to the clipboard
- Shows a “Link copied” toast as feedback
Translation system with custom overrides
A new localization system that supports translating all UI text, with the ability to override any string.Base locale files are loaded dynamically from CDN based on the Shopify storefront language. Translation keys use dot notation (e.g.drawer.home.emptyCalloutTitle), with support for {{variable}} interpolation and pluralization via One / Other key suffixes.You can override any translation key by passing a translations object when initializing the SDK. Overrides are applied per language after the base locale loads - for example, changing “Add to Cart” to “Add to Bag”, or “Save” to “Add to Wishlist”.Custom product detail transforms
You can customize how product data is displayed using transform functions passed through SDK options.Available transforms:- title - customize the product title (e.g. append a brand name)
- description - modify the product description
- variantTitle - customize how variant titles are displayed
- badges - add, remove, or modify product badges (e.g. “New Arrival”, “On Sale”)
- optionValues - filter, reorder, or modify product option values before rendering (e.g. hide unavailable sizes)