For Shopify theme developers, the handoff from a selected charm to the correct cart line matters more than the hotspot itself. This example traces the variant IDs, personalization properties, and checkout discount through that handoff.
A shopper sees a charm she loves, but still has to work out which chain it fits, which other charms go with it, and whether the engraving belongs to this piece or another one in the order. Astrid & Miyu gives each of those decisions a place on its shopping journey. Here is how a Shopify jewelry store can adopt the same sequence.
This walkthrough refers to AMAKA JANE’s public Astrid & Miyu design project and to the brand’s live UK charm page. The screenshots are excerpts from the design project. They show the shopping interface and example offers, while sales and conversion would require order data.
Start with a finished stack
The opening shows a finished necklace against a slate-blue background. Before the shopper sees individual prices or filters, she can see the kind of combination the page will help her build. The muted blue and warm sand let the gold carry the color. Serif italics work for the editorial headline, while the price, labels, and navigation stay in a restrained sans serif.
For a Shopify collection, use that first image to establish what a complete stack looks like. Keep the next action close by: choose a chain or choose a charm type. A shopper who came in for a particular birthstone can still reach the products without reading the full story.
Let shoppers check the fitting first
A charm that looks right may still be wrong for the chain. On the UK page, three routes explain that choice before the shopper enters a large collection. Starting prices below are the amounts displayed on that page at the time of review.
| Route | How it attaches | What to show next |
|---|---|---|
| Clip, from £40 | A detachable clip fits an eligible link, clasp, or hoop. The brand lists plated sterling silver options. | Links to compatible necklaces, bracelets, or earrings. |
| Click, from £80 | A 9k solid gold charm closes around a compatible bead or cord. | Story Strands and compatible birthstone beaded pieces. |
| Story, from £40 | The brand fits 9k gold charms to a made-to-order Story Chain or as part of its welding service. | A bespoke builder or the relevant in-store service. |
Use a product metafield for the fitting family if every variant of a product shares the same fitting. Use a variant-level field when the compatibility changes with the variant. Give each collection route a name the customer recognizes from the label on the card. Check a known compatible and a known incompatible chain against each route before using the data in filters.
Show why the next charm belongs
Under “Curated by you,” fine lines connect the jewelry to short descriptions. The Sagittarius charm stands for a mother’s zodiac sign; the tanzanite represents her birthstone. A key marks a first home. The annotated image gives the reader a reason to choose a second charm and makes its position in the stack visible.
A Shopify section can pair an editorial image with a list of the exact variants shown. Each hotspot should point to the corresponding product card, and the card should still make sense on a phone where the shopper taps it on its own. In the supplied example, the hotspot highlights a card. A store implementation should also check that people can get to the corresponding card with a keyboard, see which card is selected, and reach the variant even when the image is below the fold.
The cards serve two separate decisions. “Clip Charm” tells the shopper what fits. “Engravable,” “Wisdom,” or “Choose Your Initial” tells her what is special about that piece. For welded jewelry, the project gives booking, chains, stores, clasps, warranty, and questions their own navigation. The UK current warranty policy lists two years for welded jewelry, with a £30 charge for eligible UK repairs outside that period. Link to the current policy when adapting a service page.
Implement the handoff to the cart in Shopify
Store the personalization on the right item
Place the engraving input inside the Shopify product form. An input named properties[Engraving] associates the text with that line. Choose a separate variant when the initial is a stocked SKU with its own availability or price. If engraving costs extra, represent the charge with a priced variant or another actual chargeable item. An order-line property carries text.
For an ordinary product form, the original sample checks the boolean metafield custom.is_engravable and then renders an input limited to eight characters. Also validate the shop’s actual character rules and check how the store prints the value on an order or fulfillment document. The storefront input limit is one layer of that check.
Send the actual variants as a group
Use the Shopify Ajax Cart API with the active locale URL. Map each chosen product to a real variant ID, quantity, and its own properties. Include the chain as a separate line if the promise is to add the full stack. The following excerpt assumes the shopper’s available selections have already been checked.
const items = selections.map(({ variantId, engraving }) => ({ id: variantId, quantity: 1, ...(engraving && { properties: { Personalisation: engraving } }), })); const response = await fetch(window.Shopify.routes.root + 'cart/add.js', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ items }), }); if (!response.ok) throw new Error('The selected items could not be added'); Price each card from the selected variant in the current market. The original sample uses a handwritten pound price and calculates a display estimate when three charms are checked. Configure the actual discount in Shopify, and show the amount the cart or checkout calculates. A discount for three eligible charms and a discount on a specific bundle are different rules; test which products count toward the offer.
For a store-level test, start with one charm, then a chain and three charms, then try one unavailable variant. Check the cart lines, their properties, localized price, the discount applied, and the message a shopper sees if a selection cannot be added. Try two copies of the same variant with different engravings and verify each property stays on the intended line.
When to use this pattern
CODESTAL’s silver jewelry case emphasizes the identity and weight of an individual piece. A charm stack asks the shopper to build a group of compatible pieces. Start with fitting and product facts when customers ask whether something will fit. Add annotated stories when they understand the fittings but need help imagining a finished combination. Put the stock, personalization, and discount rules behind those paths before treating the section as a live store feature.
Original Shopify Section example
The supplied Liquid, CSS, JavaScript, and schema are reproduced below for reference. The sample needs store-specific product bindings, actual variant prices, availability and error handling, and a configured discount before deployment. No live checkout result is assumed.
{%- comment -%} 文件:sections/astrid-charm-stack-builder.liquid 设计参考:Luxury Personalized Jewelry Store Website Design - ASTRID & MIYU (by AMAKA JANE) 功能:柔雾轻奢风「Curate Your Stack」故事引线热点图 + 双胶囊徽章单品卡 + 刻字录入与整套一键加购 {%- endcomment -%} <link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link href="https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,500;0,600;1,500&family=Plus+Jakarta+Sans:wght@400;500;600;700&display=swap" rel="stylesheet"> <style> .am-sec-{{ section.id }} { --am-bg-cream: #FAF7F2; --am-bg-sand: #EFE8DA; --am-slate-blue: #8AA0AE; --am-sage: #D8E2DC; --am-ink: #1A1A1A; --am-muted: #6E6A63; --am-border: #E2D9C8; --am-font-serif: 'Cormorant Garamond', Georgia, serif; --am-font-sans: 'Plus Jakarta Sans', -apple-system, BlinkMacSystemFont, sans-serif; background-color: var(--am-bg-cream); color: var(--am-ink); font-family: var(--am-font-sans); padding: {{ section.settings.padding_top }}px 0 {{ section.settings.padding_bottom }}px; } .am-container { max-width: 1320px; margin: 0 auto; padding: 0 24px; } /* 顶部柔雾轻奢标题区 */ .am-header { text-align: center; max-width: 680px; margin: 0 auto 48px; } .am-eyebrow { display: inline-block; background-color: var(--am-bg-sand); color: var(--am-ink); font-size: 0.75rem; font-weight: 600; letter-spacing: 0.12em; text-transform: uppercase; padding: 6px 14px; border-radius: 999px; margin-bottom: 14px; } .am-title { font-family: var(--am-font-serif); font-size: clamp(2.25rem, 4.2vw, 3.5rem); font-weight: 500; line-height: 1.08; margin: 0 0 12px; color: var(--am-ink); } .am-title em { font-style: italic; font-weight: 500; } .am-subtitle { font-size: 0.9375rem; line-height: 1.6; color: var(--am-muted); margin: 0; } /* 3 列扣具机制科普条:CLIP / CLICK / STORY CHARMS */ .am-mechanism-strip { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; margin-bottom: 48px; } @media screen and (max-width: 768px) { .am-mechanism-strip { grid-template-columns: 1fr; } } .am-mech-card { background-color: var(--am-bg-sand); border: 1px solid var(--am-border); border-radius: 14px; padding: 20px 22px; display: flex; justify-content: space-between; align-items: flex-start; gap: 12px; } .am-mech-title { font-size: 0.875rem; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; margin: 0 0 6px; } .am-mech-desc { font-size: 0.8125rem; line-height: 1.45; color: var(--am-muted); margin: 0; } .am-mech-price { background-color: #FFFFFF; color: var(--am-ink); font-size: 0.75rem; font-weight: 700; padding: 4px 10px; border-radius: 999px; white-space: nowrap; } /* 主体双栏:左侧故事引线热点图 + 右侧叠戴配置清单 */ .am-stack-layout { display: grid; grid-template-columns: 5fr 7fr; gap: 36px; align-items: start; } @media screen and (max-width: 960px) { .am-stack-layout { grid-template-columns: 1fr; } } /* 左侧故事热点画布 */ .am-look-canvas { position: relative; border-radius: 20px; overflow: hidden; background-color: var(--am-slate-blue); aspect-ratio: 4 / 5; } .am-look-canvas img { width: 100%; height: 100%; object-fit: cover; } .am-look-placeholder { width: 100%; height: 100%; display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 32px; text-align: center; color: #FFFFFF; background: linear-gradient(160deg, #8AA0AE 0%, #6E8594 100%); } .am-look-placeholder h3 { font-family: var(--am-font-serif); font-size: 2rem; font-style: italic; margin: 0 0 8px; } /* 图上情感故事锚点(Story Pin) */ .am-story-pin { position: absolute; transform: translate(-50%, -50%); display: inline-flex; align-items: center; gap: 8px; background: rgba(255, 255, 255, 0.94); color: var(--am-ink); border: 1px solid var(--am-ink); padding: 5px 12px 5px 6px; border-radius: 999px; font-size: 0.75rem; font-weight: 600; cursor: pointer; box-shadow: 0 4px 14px rgba(0, 0, 0, 0.12); transition: transform 0.2s ease, background-color 0.2s ease; } .am-story-pin:hover, .am-story-pin.is-active { background: var(--am-ink); color: #FFFFFF; transform: translate(-50%, -50%) scale(1.06); } .am-pin-num { width: 20px; height: 20px; border-radius: 50%; background: var(--am-bg-sand); color: var(--am-ink); display: inline-flex; align-items: center; justify-content: center; font-size: 0.6875rem; font-weight: 700; } /* 右侧双徽章单品卡片网格 */ .am-charm-list { display: grid; grid-template-columns: repeat(2, 1fr); gap: 18px; } @media screen and (max-width: 600px) { .am-charm-list { grid-template-columns: 1fr; } } .am-charm-card { background: #FFFFFF; border: 1.5px solid var(--am-border); border-radius: 16px; padding: 18px; display: flex; flex-direction: column; justify-content: space-between; transition: border-color 0.2s ease, box-shadow 0.2s ease; } .am-charm-card.is-highlighted { border-color: var(--am-ink); box-shadow: 0 8px 24px rgba(26, 26, 26, 0.08); } /* 原案标志性:双胶囊徽章(扣具机制 + 寓意/可刻字) */ .am-badge-row { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 12px; } .am-badge-mech { font-size: 0.6875rem; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; padding: 4px 9px; border-radius: 999px; background-color: var(--am-bg-sand); color: var(--am-ink); } .am-badge-meaning { font-size: 0.6875rem; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; padding: 4px 9px; border-radius: 999px; background-color: var(--am-sage); color: var(--am-ink); } .am-story-quote { font-family: var(--am-font-serif); font-style: italic; font-size: 1.0625rem; color: var(--am-muted); margin: 0 0 6px; } .am-charm-title { font-size: 0.9375rem; font-weight: 600; margin: 0 0 4px; color: var(--am-ink); } .am-charm-metal { font-size: 0.75rem; color: var(--am-muted); margin: 0 0 12px; } /* 行内刻字或首字母定制输入框 */ .am-custom-input { width: 100%; box-sizing: border-box; border: 1px solid var(--am-border); background: var(--am-bg-cream); border-radius: 8px; padding: 8px 10px; font-size: 0.75rem; margin-bottom: 12px; color: var(--am-ink); } .am-card-bottom { display: flex; justify-content: space-between; align-items: center; padding-top: 12px; border-top: 1px solid var(--am-border); } .am-price { font-size: 0.9375rem; font-weight: 700; } .am-check-label { display: inline-flex; align-items: center; gap: 6px; font-size: 0.75rem; font-weight: 600; cursor: pointer; } /* 底部套装汇总与一键加购栏 */ .am-bundle-bar { margin-top: 24px; background: var(--am-bg-sand); border: 1px solid var(--am-border); border-radius: 16px; padding: 20px 24px; display: flex; flex-wrapSource:https://dev.to/weswoodtc/shopify-charm-stacks-with-line-item-properties-and-ajax-cart-1fep Related posts

Build a VR Exposure-Therapy Prototype with WebXR and Three.js
When Age Checks Spill Beyond Video: What Google's Gmail Warning Means for Australia’s Under-18 Internet Rules
Stop Paying for AI Design Tools: How to Build UI Prototypes Locally with OpenDesign





