Shoppers assemble a bundle from sections you define (“pick 3 coffees, pick 2 mugs”) and get a discount that can grow with the size of the box. Needs: the Storesynk AI app on the Pro plan.
In the app
Section titled “In the app”- Open Discounts & Bundles, click Create, and pick Mix & match bundle.
- Add sections: a name, an image, the product pool, and the minimum and maximum items. A minimum of 0 makes the section optional.
- Choose the discount: a single rule or tiers by item count. Types are percentage, fixed amount, set price, free shipping, and (in tiers) cheapest item free. You can apply it to the whole selection or to specific sections.
- Pick the cart presentation: grouped as one bundle line, or separate lines discounted automatically.
- Set the title, tick Show the mix & match widget on all pool products’ pages, set the dates, and mark it Active.
Limits: 25 mix & match bundles per shop, 10 sections, 30 products per section, 60 distinct products across the bundle, 6 tiers. Fixed-amount and set-price discounts are recorded in the shop currency and only apply to carts in that currency.
On your storefront
Section titled “On your storefront”Two placements: inside a product page’s <storesynk-product>, or on a standalone builder page with handle="…" naming the bundle (client-rendered only). Four clone containers nest, and each one’s first child is its template:
storesynk-mix-match → first child: the per-bundle template (mix-match-offer) mix-match-offer mix-match-section-list → first child: mix-match-section mix-match-section toggle-section → the disclosure header mix-match-item-list → first child: the pool card (storesynk-product) mix-match-selection-list → first child: the pick thumbnail<storesynk-mix-match> <mix-match-offer> <show-mix-match-title></show-mix-match-title> <show-mix-match-tier-hint></show-mix-match-tier-hint>
<mix-match-section-list> <mix-match-section> <toggle-section> <button type="button"> <show-section-title></show-section-title> <show-section-requirement></show-section-requirement> <show-section-count></show-section-count> </button> </toggle-section> <mix-match-item-list> <storesynk-product> <show-image><img alt="" /></show-image> <show-title></show-title> <show-price></show-price> <change-option group="1"><select><option>Choose</option></select></change-option> <add-mix-match-item><button type="button">Add</button></add-mix-match-item> <decrease-mix-match-item><button type="button" aria-label="Remove one">−</button></decrease-mix-match-item> <show-item-quantity></show-item-quantity> <increase-mix-match-item><button type="button" aria-label="Add one more">+</button></increase-mix-match-item> </storesynk-product> </mix-match-item-list> </mix-match-section> </mix-match-section-list>
<mix-match-selection-list max="4"> <span><show-pick-image></show-pick-image><show-pick-quantity></show-pick-quantity></span> <show-selection-overflow></show-selection-overflow> </mix-match-selection-list> <show-mix-match-original-total></show-mix-match-original-total> <show-mix-match-total></show-mix-match-total> <p>You save <show-mix-match-savings></show-mix-match-savings></p> <add-mix-match-to-cart><button type="button">Add box to cart</button></add-mix-match-to-cart> </mix-match-offer></storesynk-mix-match>- The accordion drives itself: the first unmet section opens, and a met section collapses to the next.
<toggle-section>and the item list form a proper disclosure; do not add your own roles. - Pool cards are real products fed by the engine, so option pickers and prices work. Give them no
handle. - The increase, decrease, and remove controls are the one family the engine does not name. Give each an
aria-label. - Prices are advisory. The app’s discount function applies the real discount at checkout. The add button stays disabled until every section is within its limits and sends the whole box in one cart update.
storesynk-mix-match[ss-empty], storesynk-mix-match[ss-loading] { display: none; }mix-match-offer, mix-match-section-list, mix-match-section, mix-match-selection-list { display: block; }mix-match-item-list:not([hidden]) { display: grid; grid-template-columns: repeat(auto-fill, minmax(130px, 1fr)); gap: 10px; }storesynk-product[ss-selected] { outline: 2px solid #111; }add-mix-match-to-cart[ss-incomplete] button { opacity: .5; cursor: not-allowed; }States
Section titled “States”| Attribute | Set on | Meaning |
|---|---|---|
ss-empty, ss-loading | storesynk-mix-match | nothing live, or fetching |
ss-open, ss-met | mix-match-section | section expanded; section minimum reached |
ss-selected | pool storesynk-product | the card is in the box |
ss-max | add-mix-match-item, increase-mix-match-item | the section is full |
ss-incomplete | add-mix-match-to-cart | a section is outside its limits |
The engine also sets --ss-progress (0 to 1) on <show-section-progress> for a progress bar.