One copy-paste HTML file: a live product with options, add-to-cart, and a cart drawer.
One HTML file, no build step, no install.
What you need first
Section titled “What you need first”There is no public demo store yet, so replace the placeholders with your own values:
- Store domain:
your-store.myshopify.com - Public Storefront API token:
your-public-storefront-token - A product handle published to that token’s channel (the last URL segment, e.g.
classic-snowboard)
Connect your store gets you the first two.
The file
Section titled “The file”Save this as index.html, replace the three placeholders, and open it:
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>My first Storesynk page</title> <style> body { font-family: system-ui, sans-serif; color: #1a1a1a; margin: 0; } .page { max-width: 900px; margin: 40px auto; padding: 0 24px; } .topbar { display: flex; justify-content: flex-end; margin-bottom: 24px; } open-cart { background: #1a1a1a; color: #fff; border-radius: 8px; padding: 8px 14px; cursor: pointer; font-weight: 600; } .product { display: grid; grid-template-columns: 1fr 1fr; gap: 40px; } .main-image img { width: 100%; aspect-ratio: 1; object-fit: cover; border-radius: 12px; } .details { display: flex; flex-direction: column; gap: 14px; } .price-row { display: flex; align-items: baseline; gap: 12px; } show-price { font-size: 22px; font-weight: 600; } show-compare-price { color: #999; text-decoration: line-through; } .option-group { display: flex; flex-direction: column; gap: 6px; } .option-values { display: flex; flex-wrap: wrap; gap: 8px; } .option-pill { padding: 8px 16px; border: 1px solid #ddd; border-radius: 8px; cursor: pointer; user-select: none; } .option-pill[ss-active] { background: #1a1a1a; color: #fff; } /* engine sets [ss-active] */ .option-pill[ss-unavailable] { opacity: .35; text-decoration: line-through; } add-to-cart button { width: 100%; background: #1a1a1a; color: #fff; padding: 14px; border: 0; border-radius: 8px; cursor: pointer; font: inherit; font-weight: 600; } add-to-cart[ss-loading] button { opacity: .4; cursor: wait; } add-to-cart[ss-out-of-stock] button, add-to-cart[ss-unavailable] button { background: #999; cursor: not-allowed; } /* Cart drawer */ .drawer { position: fixed; top: 0; right: 0; height: 100%; width: 340px; background: #fff; box-shadow: -8px 0 24px rgba(0,0,0,.12); padding: 20px; transform: translateX(100%); transition: transform .25s ease, visibility .25s; overflow: auto; display: flex; flex-direction: column; gap: 8px; visibility: hidden; /* a closed drawer must be untabbable, not just off-screen */ } .drawer[ss-open] { transform: translateX(0); visibility: visible; } /* engine sets [ss-open] */ .drawer .close { align-self: flex-end; border: 0; background: none; font-size: 22px; cursor: pointer; } cart-line { display: flex; gap: 10px; align-items: center; padding: 10px 0; border-bottom: 1px solid #f0f0f0; } cart-line[ss-loading] { opacity: .5; pointer-events: none; } /* engine sets [ss-loading] */ .cart-img img { width: 48px; height: 48px; object-fit: cover; border-radius: 6px; display: block; } .muted { color: #888; font-size: 12px; } .qty { display: flex; align-items: center; gap: 6px; } .qty increase-line-quantity, .qty decrease-line-quantity { width: 24px; height: 24px; display: flex; align-items: center; justify-content: center; border: 1px solid #ddd; background: #f7f7f7; border-radius: 4px; cursor: pointer; } .cart-empty-message { display: none; color: #888; } storesynk-cart[ss-empty] .cart-empty-message { display: block; } /* engine sets [ss-empty] */ .cart-foot { margin-top: auto; display: flex; flex-direction: column; gap: 10px; padding-top: 12px; } .checkout-btn { display: block; text-align: center; background: #1a1a1a; color: #fff; padding: 12px; border-radius: 8px; text-decoration: none; } </style></head><body> <!-- Replace domain + token with your own store's values (see "Connect your store"). --> <storesynk-store domain="your-store.myshopify.com" token="your-public-storefront-token">
<div class="page"> <div class="topbar"> <open-cart>Cart · <show-cart-count>0</show-cart-count></open-cart> </div>
<!-- Replace with a real product handle from your store. --> <storesynk-product handle="your-product-handle"> <div class="product"> <show-media main sizes="(max-width: 700px) 100vw, 450px" class="main-image"> <img alt="" /> </show-media>
<div class="details"> <h1><show-title></show-title></h1>
<div class="price-row"> <show-price></show-price> <show-compare-price></show-compare-price> </div>
<!-- Positional option pickers: work for ANY product. Groups the product doesn't have hide themselves. --> <change-option group="1" class="option-group"> <show-option-label></show-option-label> <div class="option-values"> <option-value class="option-pill"><show-option-title></show-option-title></option-value> </div> </change-option> <change-option group="2" class="option-group"> <show-option-label></show-option-label> <div class="option-values"> <option-value class="option-pill"><show-option-title></show-option-title></option-value> </div> </change-option> <change-option group="3" class="option-group"> <show-option-label></show-option-label> <div class="option-values"> <option-value class="option-pill"><show-option-title></show-option-title></option-value> </div> </change-option>
<add-to-cart text-out-of-stock="Sold out" text-unavailable="Unavailable"> <button type="button">Add to cart</button> </add-to-cart> </div> </div> </storesynk-product> </div>
<!-- Cart drawer: opens on add-to-cart, and via the open-cart button. --> <storesynk-cart class="drawer" open-on-add close-on-outside> <close-cart class="close">×</close-cart> <h2>Your cart</h2> <p class="cart-empty-message">Your cart is empty.</p>
<cart-line-list> <!-- First cart-line = the per-line template; cloned per cart line. --> <cart-line> <show-line-image class="cart-img"></show-line-image> <div style="flex:1"> <show-line-title></show-line-title> <show-line-variant class="muted"></show-line-variant> <show-line-price></show-line-price> </div> <div class="qty"> <decrease-line-quantity>−</decrease-line-quantity> <show-line-quantity></show-line-quantity> <increase-line-quantity>+</increase-line-quantity> </div> <remove-cart-line class="muted" style="cursor:pointer">×</remove-cart-line> </cart-line> </cart-line-list>
<div class="cart-foot"> <div>Total: <show-cart-total></show-cart-total></div> <checkout-link><a class="checkout-btn" href="#">Checkout →</a></checkout-link> </div> </storesynk-cart>
</storesynk-store>
<!-- The Storesynk elements bundle (rolling 0.1 channel). --> <script type="module" src="https://cdn.storesynk.io/elements/0.1/storesynk.js"></script></body></html>What just happened
Section titled “What just happened”<storesynk-store>connected to your store and set up the cart and money formatting.<storesynk-product>fetched one product; theshow-*tags and option pickers filled themselves.<add-to-cart>wrote a real Shopify cart and the drawer opened.
The CSS in <head> is example styling. Replace all of it.
If the page stays blank
Section titled “If the page stays blank”Usually a wrong token, a missing scope, or an unpublished product. The smoke test in Connect your store catches all three; Nothing renders covers markup causes.
Next: Connect your store